@@ -69,7 +69,10 @@ public class FailureStoreSecurityRestIT extends ESRestTestCase {
6969 @ ClassRule
7070 public static ElasticsearchCluster cluster = ElasticsearchCluster .local ()
7171 .apply (SecurityOnTrialLicenseRestTestCase .commonTrialSecurityClusterConfig )
72+ .nodes (5 )
7273 .feature (FeatureFlag .FAILURE_STORE_ENABLED )
74+ .setting ("logger.rest.suppressed" , "TRACE" )
75+ .setting ("logger.org.elasticsearch.transport.TransportService.tracer" , "trace" )
7376 .build ();
7477
7578 @ Override
@@ -1931,19 +1934,11 @@ public void testModifyingFailureStoreBackingIndices() throws Exception {
19311934 String failureIndexName = backingIndices .v2 ();
19321935
19331936 createUser (MANAGE_ACCESS , PASSWORD , MANAGE_ACCESS );
1934- upsertRole ( Strings . format ( """
1937+ createOrUpdateRoleAndApiKey ( MANAGE_ACCESS , MANAGE_ACCESS , """
19351938 {
19361939 "cluster": ["all"],
19371940 "indices": [{"names": ["test*"], "privileges": ["manage"]}]
1938- }""" ), MANAGE_ACCESS );
1939- createAndStoreApiKey (MANAGE_ACCESS , randomBoolean () ? null : """
1940- {
1941- "role": {
1942- "cluster": ["all"],
1943- "indices": [{"names": ["test*"], "privileges": ["manage"]}]
1944- }
1945- }
1946- """ );
1941+ }""" );
19471942 assertOK (addFailureStoreBackingIndex (MANAGE_ACCESS , "test1" , failureIndexName ));
19481943 assertDataStreamHasDataAndFailureIndices ("test1" , dataIndexName , failureIndexName );
19491944
@@ -1955,58 +1950,34 @@ public void testModifyingFailureStoreBackingIndices() throws Exception {
19551950 expectThrows (() -> addFailureStoreBackingIndex (MANAGE_ACCESS , "test1" , failureIndexName ), 403 );
19561951
19571952 // let's change that
1958- upsertRole ( Strings . format ( """
1953+ createOrUpdateRoleAndApiKey ( MANAGE_ACCESS , MANAGE_ACCESS , """
19591954 {
19601955 "cluster": ["all"],
19611956 "indices": [{"names": ["test*", ".fs*"], "privileges": ["manage"]}]
1962- }""" ), MANAGE_ACCESS );
1963- createOrUpdateApiKey (MANAGE_ACCESS , randomBoolean () ? null : """
1964- {
1965- "role": {
1966- "cluster": ["all"],
1967- "indices": [{"names": ["test*", ".fs*"], "privileges": ["manage"]}]
1968- }
1969- }
1970- """ );
1957+ }""" );
19711958
19721959 // adding should succeed now
19731960 assertOK (addFailureStoreBackingIndex (MANAGE_ACCESS , "test1" , failureIndexName ));
19741961 assertDataStreamHasDataAndFailureIndices ("test1" , dataIndexName , failureIndexName );
19751962
19761963 createUser (MANAGE_FAILURE_STORE_ACCESS , PASSWORD , MANAGE_FAILURE_STORE_ACCESS );
1977- upsertRole ( Strings . format ( """
1964+ createOrUpdateRoleAndApiKey ( MANAGE_FAILURE_STORE_ACCESS , MANAGE_FAILURE_STORE_ACCESS , """
19781965 {
19791966 "cluster": ["all"],
19801967 "indices": [{"names": ["test*"], "privileges": ["manage_failure_store"]}]
1981- }""" ), MANAGE_FAILURE_STORE_ACCESS );
1982- createAndStoreApiKey (MANAGE_FAILURE_STORE_ACCESS , randomBoolean () ? null : """
1983- {
1984- "role": {
1985- "cluster": ["all"],
1986- "indices": [{"names": ["test*"], "privileges": ["manage_failure_store"]}]
1987- }
1988- }
1989- """ );
1968+ }""" );
19901969
19911970 // manage_failure_store can only remove the failure backing index, but not add it
19921971 assertOK (removeFailureStoreBackingIndex (MANAGE_FAILURE_STORE_ACCESS , "test1" , failureIndexName ));
19931972 assertDataStreamHasNoFailureIndices ("test1" , dataIndexName );
19941973 expectThrows (() -> addFailureStoreBackingIndex (MANAGE_FAILURE_STORE_ACCESS , "test1" , failureIndexName ), 403 );
19951974
19961975 // not even with access to .fs*
1997- upsertRole ( Strings . format ( """
1976+ createOrUpdateRoleAndApiKey ( MANAGE_FAILURE_STORE_ACCESS , MANAGE_FAILURE_STORE_ACCESS , """
19981977 {
19991978 "cluster": ["all"],
20001979 "indices": [{"names": ["test*", ".fs*"], "privileges": ["manage_failure_store"]}]
2001- }""" ), MANAGE_FAILURE_STORE_ACCESS );
2002- createOrUpdateApiKey (MANAGE_FAILURE_STORE_ACCESS , randomBoolean () ? null : """
2003- {
2004- "role": {
2005- "cluster": ["all"],
2006- "indices": [{"names": ["test*", ".fs*"], "privileges": ["manage_failure_store"]}]
2007- }
2008- }
2009- """ );
1980+ }""" );
20101981 expectThrows (() -> addFailureStoreBackingIndex (MANAGE_FAILURE_STORE_ACCESS , "test1" , failureIndexName ), 403 );
20111982 }
20121983
@@ -2055,9 +2026,199 @@ public void testDataStreamApi() {
20552026 // test data stream stats
20562027 }
20572028
2058- public void testAliasBasedAccess () {
2059- // test alias based access with failure store
2060- // test filtered alias based access with failure store
2029+ public void testAliasBasedAccess () throws Exception {
2030+ List <String > docIds = setupDataStream ();
2031+ assertThat (docIds .size (), equalTo (2 ));
2032+ assertThat (docIds , hasItem ("1" ));
2033+ String dataDocId = "1" ;
2034+ String failuresDocId = docIds .stream ().filter (id -> false == id .equals (dataDocId )).findFirst ().get ();
2035+
2036+ List <String > otherDocIds = setupOtherDataStream ();
2037+ assertThat (otherDocIds .size (), equalTo (2 ));
2038+ assertThat (otherDocIds , hasItem ("3" ));
2039+ String otherDataDocId = "3" ;
2040+ String otherFailuresDocId = otherDocIds .stream ().filter (id -> false == id .equals (otherDataDocId )).findFirst ().get ();
2041+
2042+ final Tuple <String , String > backingIndices = getSingleDataAndFailureIndices ("test1" );
2043+ final String dataIndexName = backingIndices .v1 ();
2044+ final String failureIndexName = backingIndices .v2 ();
2045+
2046+ final String aliasName = "my-alias" ;
2047+ final String username = "user" ;
2048+ final String roleName = "role" ;
2049+
2050+ createUser (username , PASSWORD , roleName );
2051+ // manage is required to add the alias to the data stream
2052+ createOrUpdateRoleAndApiKey (username , roleName , Strings .format ("""
2053+ {
2054+ "cluster": ["all"],
2055+ "indices": [
2056+ {
2057+ "names": ["test1", "%s", "other1"],
2058+ "privileges": ["manage"]
2059+ }
2060+ ]
2061+ }
2062+ """ , aliasName ));
2063+
2064+ addAlias (username , "test1" , aliasName , "" );
2065+ addAlias (username , "other1" , aliasName , "" );
2066+ assertThat (fetchAliases (username , "test1" ), containsInAnyOrder (aliasName ));
2067+ expectSearchThrows (username , new Search (randomFrom (aliasName + "::data" , aliasName )), 403 );
2068+ expectSearchThrows (username , new Search (randomFrom (aliasName + "::failures" )), 403 );
2069+
2070+ createOrUpdateRoleAndApiKey (username , roleName , Strings .format ("""
2071+ {
2072+ "cluster": ["all"],
2073+ "indices": [
2074+ {
2075+ "names": ["%s"],
2076+ "privileges": ["read_failure_store"]
2077+ }
2078+ ]
2079+ }
2080+ """ , aliasName ));
2081+ expectSearch (username , new Search (aliasName + "::failures" ), failuresDocId , otherFailuresDocId );
2082+ expectSearchThrows (
2083+ username ,
2084+ new Search (randomFrom (aliasName + "::data" , "my-alias::failures" , dataIndexName , failureIndexName )),
2085+ 403
2086+ );
2087+
2088+ createOrUpdateRoleAndApiKey (username , roleName , Strings .format ("""
2089+ {
2090+ "cluster": ["all"],
2091+ "indices": [
2092+ {
2093+ "names": ["%s"],
2094+ "privileges": ["read"]
2095+ }
2096+ ]
2097+ }
2098+ """ , aliasName ));
2099+ expectSearch (username , new Search (randomFrom (aliasName + "::data" )), dataDocId , otherDataDocId );
2100+ expectSearchThrows (username , new Search (aliasName + "::failures" ), 403 );
2101+
2102+ expectThrows (() -> removeAlias (username , "test1" , aliasName ), 403 );
2103+ createOrUpdateRoleAndApiKey (username , roleName , Strings .format ("""
2104+ {
2105+ "cluster": ["all"],
2106+ "indices": [
2107+ {
2108+ "names": ["test1", "%s", "other1"],
2109+ "privileges": ["manage"]
2110+ }
2111+ ]
2112+ }
2113+ """ , aliasName ));
2114+ removeAlias (username , "test1" , aliasName );
2115+ removeAlias (username , "other1" , aliasName );
2116+
2117+ final String filteredAliasName = "my-filtered-alias" ;
2118+ createOrUpdateRoleAndApiKey (username , roleName , Strings .format ("""
2119+ {
2120+ "cluster": ["all"],
2121+ "indices": [
2122+ {
2123+ "names": ["test1", "%s", "other1"],
2124+ "privileges": ["manage"]
2125+ }
2126+ ]
2127+ }
2128+ """ , filteredAliasName ));
2129+ addAlias (username , "test1" , filteredAliasName , """
2130+ {
2131+ "term": {
2132+ "document.source.name": "jack"
2133+ }
2134+ }
2135+ """ );
2136+ addAlias (username , "other1" , filteredAliasName , """
2137+ {
2138+ "term": {
2139+ "document.source.name": "jack"
2140+ }
2141+ }
2142+ """ );
2143+ assertThat (fetchAliases (username , "test1" ), containsInAnyOrder (filteredAliasName ));
2144+ assertThat (fetchAliases (username , "other1" ), containsInAnyOrder (filteredAliasName ));
2145+
2146+ createOrUpdateRoleAndApiKey (username , roleName , Strings .format ("""
2147+ {
2148+ "cluster": ["all"],
2149+ "indices": [
2150+ {
2151+ "names": ["%s"],
2152+ "privileges": ["read", "read_failure_store"]
2153+ }
2154+ ]
2155+ }
2156+ """ , filteredAliasName ));
2157+
2158+ expectSearch (username , new Search (randomFrom (filteredAliasName + "::data" , filteredAliasName )));
2159+ // the alias filter is not applied to the failure store
2160+ expectSearch (username , new Search (filteredAliasName + "::failures" ), failuresDocId , otherDataDocId );
2161+ }
2162+
2163+ private void createOrUpdateRoleAndApiKey (String username , String roleName , String roleDescriptor ) throws IOException {
2164+ upsertRole (roleDescriptor , roleName );
2165+ createOrUpdateApiKey (username , randomBoolean () ? null : Strings .format ("""
2166+ {
2167+ "%s": %s
2168+ }
2169+ """ , roleName , roleDescriptor ));
2170+ }
2171+
2172+ private void addAlias (String user , String dataStream , String alias , String filter ) throws IOException {
2173+ aliasAction (user , "add" , dataStream , alias , filter );
2174+ }
2175+
2176+ private void removeAlias (String user , String dataStream , String alias ) throws IOException {
2177+ aliasAction (user , "remove" , dataStream , alias , "" );
2178+ }
2179+
2180+ private void aliasAction (String user , String action , String dataStream , String alias , String filter ) throws IOException {
2181+ Request request = new Request ("POST" , "/_aliases" );
2182+ if (filter == null || filter .isEmpty ()) {
2183+ request .setJsonEntity (Strings .format ("""
2184+ {
2185+ "actions": [
2186+ {
2187+ "%s": {
2188+ "index": "%s",
2189+ "alias": "%s"
2190+ }
2191+ }
2192+ ]
2193+ }
2194+ """ , action , dataStream , alias ));
2195+ } else {
2196+ request .setJsonEntity (Strings .format ("""
2197+ {
2198+ "actions": [
2199+ {
2200+ "%s": {
2201+ "index": "%s",
2202+ "alias": "%s",
2203+ "filter": %s
2204+ }
2205+ }
2206+ ]
2207+ }
2208+ """ , action , dataStream , alias , filter ));
2209+ }
2210+ Response response = performRequestMaybeUsingApiKey (user , request );
2211+ var path = assertOKAndCreateObjectPath (response );
2212+ assertThat (path .evaluate ("acknowledged" ), is (true ));
2213+ assertThat (path .evaluate ("errors" ), is (false ));
2214+
2215+ }
2216+
2217+ private Set <String > fetchAliases (String user , String dataStream ) throws IOException {
2218+ Response response = performRequestMaybeUsingApiKey (user , new Request ("GET" , dataStream + "/_alias" ));
2219+ ObjectPath path = assertOKAndCreateObjectPath (response );
2220+ Map <String , Object > aliases = path .evaluate (dataStream + ".aliases" );
2221+ return aliases .keySet ();
20612222 }
20622223
20632224 public void testPatternExclusions () throws Exception {
@@ -2917,9 +3078,13 @@ private static void expectSearch(Response response, String... docIds) throws IOE
29173078 final SearchResponse searchResponse = SearchResponseUtils .parseSearchResponse (responseAsParser (response ));
29183079 try {
29193080 SearchHit [] hits = searchResponse .getHits ().getHits ();
2920- assertThat (hits .length , equalTo (docIds .length ));
2921- List <String > actualDocIds = Arrays .stream (hits ).map (SearchHit ::getId ).toList ();
2922- assertThat (actualDocIds , containsInAnyOrder (docIds ));
3081+ if (docIds != null ) {
3082+ assertThat (Arrays .toString (hits ), hits .length , equalTo (docIds .length ));
3083+ List <String > actualDocIds = Arrays .stream (hits ).map (SearchHit ::getId ).toList ();
3084+ assertThat (actualDocIds , containsInAnyOrder (docIds ));
3085+ } else {
3086+ assertThat (hits .length , equalTo (0 ));
3087+ }
29233088 } finally {
29243089 searchResponse .decRef ();
29253090 }
0 commit comments