Skip to content

Commit 7922694

Browse files
committed
Add test that captures the different behaviour between ::data and ::failures.
1 parent 293cd37 commit 7922694

File tree

1 file changed

+240
-1
lines changed

1 file changed

+240
-1
lines changed

x-pack/plugin/security/qa/security-trial/src/javaRestTest/java/org/elasticsearch/xpack/security/failurestore/FailureStoreSecurityRestIT.java

Lines changed: 240 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ public void setup() throws IOException {
105105
upsertRole(Strings.format("""
106106
{
107107
"cluster": ["all"],
108-
"indices": [{"names": ["test*"], "privileges": ["write", "auto_configure"]}]
108+
"indices": [{"names": ["test*", "other*"], "privileges": ["write", "auto_configure"]}]
109109
}"""), WRITE_ACCESS);
110110
}
111111

@@ -1921,6 +1921,245 @@ public void testFailureStoreAccess() throws Exception {
19211921
}
19221922
}
19231923

1924+
public void testAliasBasedAccess() throws Exception {
1925+
List<String> docIds = setupDataStream();
1926+
assertThat(docIds.size(), equalTo(2));
1927+
assertThat(docIds, hasItem("1"));
1928+
String dataDocId = "1";
1929+
String failuresDocId = docIds.stream().filter(id -> false == id.equals(dataDocId)).findFirst().get();
1930+
1931+
List<String> otherDocIds = setupOtherDataStream();
1932+
assertThat(otherDocIds.size(), equalTo(2));
1933+
assertThat(otherDocIds, hasItem("3"));
1934+
String otherDataDocId = "3";
1935+
String otherFailuresDocId = otherDocIds.stream().filter(id -> false == id.equals(otherDataDocId)).findFirst().get();
1936+
1937+
final Tuple<String, String> backingIndices = getSingleDataAndFailureIndices("test1");
1938+
final String dataIndexName = backingIndices.v1();
1939+
final String failureIndexName = backingIndices.v2();
1940+
1941+
final String aliasName = "my-alias";
1942+
final String username = "user";
1943+
final String roleName = "role";
1944+
1945+
createUser(username, PASSWORD, roleName);
1946+
// manage is required to add the alias to the data stream
1947+
createOrUpdateRoleAndApiKey(username, roleName, Strings.format("""
1948+
{
1949+
"cluster": ["all"],
1950+
"indices": [
1951+
{
1952+
"names": ["test1", "%s", "other1"],
1953+
"privileges": ["manage"]
1954+
}
1955+
]
1956+
}
1957+
""", aliasName));
1958+
1959+
addAlias(username, "test1", aliasName, "");
1960+
addAlias(username, "other1", aliasName, "");
1961+
assertThat(fetchAliases(username, "test1"), containsInAnyOrder(aliasName));
1962+
expectSearchThrows(username, new Search(randomFrom(aliasName + "::data", aliasName)), 403);
1963+
expectSearchThrows(username, new Search(randomFrom(aliasName + "::failures")), 403);
1964+
1965+
createOrUpdateRoleAndApiKey(username, roleName, Strings.format("""
1966+
{
1967+
"cluster": ["all"],
1968+
"indices": [
1969+
{
1970+
"names": ["%s"],
1971+
"privileges": ["read_failure_store"]
1972+
}
1973+
]
1974+
}
1975+
""", aliasName));
1976+
expectSearch(username, new Search(aliasName + "::failures"), failuresDocId, otherFailuresDocId);
1977+
expectSearchThrows(
1978+
username,
1979+
new Search(randomFrom(aliasName + "::data", "my-alias::failures", dataIndexName, failureIndexName)),
1980+
403
1981+
);
1982+
1983+
createOrUpdateRoleAndApiKey(username, roleName, Strings.format("""
1984+
{
1985+
"cluster": ["all"],
1986+
"indices": [
1987+
{
1988+
"names": ["%s"],
1989+
"privileges": ["read"]
1990+
}
1991+
]
1992+
}
1993+
""", aliasName));
1994+
expectSearch(username, new Search(randomFrom(aliasName + "::data")), dataDocId, otherDataDocId);
1995+
expectSearchThrows(username, new Search(aliasName + "::failures"), 403);
1996+
1997+
expectThrows(() -> removeAlias(username, "test1", aliasName), 403);
1998+
createOrUpdateRoleAndApiKey(username, roleName, Strings.format("""
1999+
{
2000+
"cluster": ["all"],
2001+
"indices": [
2002+
{
2003+
"names": ["test1", "%s", "other1"],
2004+
"privileges": ["manage"]
2005+
}
2006+
]
2007+
}
2008+
""", aliasName));
2009+
removeAlias(username, "test1", aliasName);
2010+
removeAlias(username, "other1", aliasName);
2011+
2012+
final String filteredAliasName = "my-filtered-alias";
2013+
createOrUpdateRoleAndApiKey(username, roleName, Strings.format("""
2014+
{
2015+
"cluster": ["all"],
2016+
"indices": [
2017+
{
2018+
"names": ["test1", "%s", "other1"],
2019+
"privileges": ["manage"]
2020+
}
2021+
]
2022+
}
2023+
""", filteredAliasName));
2024+
addAlias(username, "test1", filteredAliasName, """
2025+
{
2026+
"term": {
2027+
"document.source.name": "jack"
2028+
}
2029+
}
2030+
""");
2031+
addAlias(username, "other1", filteredAliasName, """
2032+
{
2033+
"term": {
2034+
"document.source.name": "jack"
2035+
}
2036+
}
2037+
""");
2038+
assertThat(fetchAliases(username, "test1"), containsInAnyOrder(filteredAliasName));
2039+
assertThat(fetchAliases(username, "other1"), containsInAnyOrder(filteredAliasName));
2040+
2041+
createOrUpdateRoleAndApiKey(username, roleName, Strings.format("""
2042+
{
2043+
"cluster": ["all"],
2044+
"indices": [
2045+
{
2046+
"names": ["%s"],
2047+
"privileges": ["read", "read_failure_store"]
2048+
}
2049+
]
2050+
}
2051+
""", filteredAliasName));
2052+
2053+
expectSearch(username, new Search(randomFrom(filteredAliasName + "::data", filteredAliasName)));
2054+
// the alias filter is not applied to the failure store
2055+
expectSearch(username, new Search(filteredAliasName + "::failures"), failuresDocId, otherFailuresDocId);
2056+
}
2057+
2058+
private void createOrUpdateRoleAndApiKey(String username, String roleName, String roleDescriptor) throws IOException {
2059+
upsertRole(roleDescriptor, roleName);
2060+
createOrUpdateApiKey(username, randomBoolean() ? null : Strings.format("""
2061+
{
2062+
"%s": %s
2063+
}
2064+
""", roleName, roleDescriptor));
2065+
}
2066+
2067+
private void addAlias(String user, String dataStream, String alias, String filter) throws IOException {
2068+
aliasAction(user, "add", dataStream, alias, filter);
2069+
}
2070+
2071+
private void removeAlias(String user, String dataStream, String alias) throws IOException {
2072+
aliasAction(user, "remove", dataStream, alias, "");
2073+
}
2074+
2075+
private void aliasAction(String user, String action, String dataStream, String alias, String filter) throws IOException {
2076+
Request request = new Request("POST", "/_aliases");
2077+
if (filter == null || filter.isEmpty()) {
2078+
request.setJsonEntity(Strings.format("""
2079+
{
2080+
"actions": [
2081+
{
2082+
"%s": {
2083+
"index": "%s",
2084+
"alias": "%s"
2085+
}
2086+
}
2087+
]
2088+
}
2089+
""", action, dataStream, alias));
2090+
} else {
2091+
request.setJsonEntity(Strings.format("""
2092+
{
2093+
"actions": [
2094+
{
2095+
"%s": {
2096+
"index": "%s",
2097+
"alias": "%s",
2098+
"filter": %s
2099+
}
2100+
}
2101+
]
2102+
}
2103+
""", action, dataStream, alias, filter));
2104+
}
2105+
Response response = performRequestMaybeUsingApiKey(user, request);
2106+
var path = assertOKAndCreateObjectPath(response);
2107+
assertThat(path.evaluate("acknowledged"), is(true));
2108+
assertThat(path.evaluate("errors"), is(false));
2109+
2110+
}
2111+
2112+
private Set<String> fetchAliases(String user, String dataStream) throws IOException {
2113+
Response response = performRequestMaybeUsingApiKey(user, new Request("GET", dataStream + "/_alias"));
2114+
ObjectPath path = assertOKAndCreateObjectPath(response);
2115+
Map<String, Object> aliases = path.evaluate(dataStream + ".aliases");
2116+
return aliases.keySet();
2117+
}
2118+
2119+
public void testPatternExclusions() throws Exception {
2120+
List<String> docIds = setupDataStream();
2121+
assertThat(docIds.size(), equalTo(2));
2122+
assertThat(docIds, hasItem("1"));
2123+
String dataDocId = "1";
2124+
String failuresDocId = docIds.stream().filter(id -> false == id.equals(dataDocId)).findFirst().get();
2125+
2126+
List<String> otherDocIds = setupOtherDataStream();
2127+
assertThat(otherDocIds.size(), equalTo(2));
2128+
assertThat(otherDocIds, hasItem("3"));
2129+
String otherDataDocId = "3";
2130+
String otherFailuresDocId = otherDocIds.stream().filter(id -> false == id.equals(otherDataDocId)).findFirst().get();
2131+
2132+
createUser("user", PASSWORD, "role");
2133+
upsertRole("""
2134+
{
2135+
"cluster": ["all"],
2136+
"indices": [
2137+
{
2138+
"names": ["test*", "other*"],
2139+
"privileges": ["read", "read_failure_store"]
2140+
}
2141+
]
2142+
}
2143+
""", "role");
2144+
createAndStoreApiKey("user", randomBoolean() ? null : """
2145+
{
2146+
"role": {
2147+
"cluster": ["all"],
2148+
"indices": [
2149+
{
2150+
"names": ["*"],
2151+
"privileges": ["read", "read_failure_store"]
2152+
}
2153+
]
2154+
}
2155+
}
2156+
""");
2157+
2158+
// no exclusion -> should return two failure docs
2159+
expectSearch("user", new Search("*::failures"), failuresDocId, otherFailuresDocId);
2160+
expectSearch("user", new Search("*::failures,-other*::failures"), failuresDocId);
2161+
}
2162+
19242163
@SuppressWarnings("unchecked")
19252164
private void expectEsql(String user, Search search, String... docIds) throws Exception {
19262165
var response = performRequestMaybeUsingApiKey(user, search.toEsqlRequest());

0 commit comments

Comments
 (0)