Skip to content

Commit baf63ed

Browse files
committed
Fix
1 parent c2baa5b commit baf63ed

File tree

2 files changed

+123
-15
lines changed

2 files changed

+123
-15
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
package org.elasticsearch.xpack.security.privilege;
9+
10+
import org.elasticsearch.client.Request;
11+
import org.elasticsearch.client.Response;
12+
import org.elasticsearch.common.settings.SecureString;
13+
import org.elasticsearch.common.settings.Settings;
14+
import org.elasticsearch.common.util.concurrent.ThreadContext;
15+
import org.elasticsearch.common.xcontent.XContentHelper;
16+
import org.elasticsearch.test.cluster.ElasticsearchCluster;
17+
import org.elasticsearch.test.cluster.FeatureFlag;
18+
import org.elasticsearch.test.rest.ESRestTestCase;
19+
import org.elasticsearch.xcontent.json.JsonXContent;
20+
import org.elasticsearch.xpack.security.SecurityOnTrialLicenseRestTestCase;
21+
import org.junit.ClassRule;
22+
23+
import java.io.IOException;
24+
import java.util.Map;
25+
26+
import static org.hamcrest.Matchers.equalTo;
27+
28+
public class FailureStoreSecurityRestIT extends ESRestTestCase {
29+
30+
@ClassRule
31+
public static ElasticsearchCluster cluster = ElasticsearchCluster.local()
32+
.apply(SecurityOnTrialLicenseRestTestCase.commonTrialSecurityClusterConfig)
33+
.feature(FeatureFlag.FAILURE_STORE_ENABLED)
34+
.build();
35+
36+
@Override
37+
protected String getTestRestCluster() {
38+
return cluster.getHttpAddresses();
39+
}
40+
41+
@Override
42+
protected Settings restAdminSettings() {
43+
String token = basicAuthHeaderValue("admin_user", new SecureString("admin-password".toCharArray()));
44+
return Settings.builder().put(ThreadContext.PREFIX + ".Authorization", token).build();
45+
}
46+
47+
public void testGetUserPrivileges() throws IOException {
48+
Request roleRequest = new Request("PUT", "/_security/role/role");
49+
roleRequest.setJsonEntity("""
50+
{
51+
"cluster": ["all"],
52+
"indices": [
53+
{
54+
"names": ["*"],
55+
"privileges": ["read", "read_failure_store"]
56+
}
57+
]
58+
}
59+
""");
60+
assertOK(adminClient().performRequest(roleRequest));
61+
62+
Request userRequest = new Request("PUT", "/_security/user/user");
63+
userRequest.setJsonEntity("""
64+
{
65+
"password": "x-pack-test-password",
66+
"roles": ["role"]
67+
}
68+
""");
69+
assertOK(adminClient().performRequest(userRequest));
70+
71+
Request request = new Request("GET", "/_security/user/_privileges");
72+
request.setOptions(
73+
request.getOptions()
74+
.toBuilder()
75+
.addHeader("Authorization", basicAuthHeaderValue("user", new SecureString("x-pack-test-password".toCharArray())))
76+
);
77+
Response response = client().performRequest(request);
78+
assertOK(response);
79+
assertThat(responseAsMap(response), equalTo(mapFromJson("""
80+
{
81+
"cluster": ["all"],
82+
"global": [],
83+
"indices": [{
84+
"names": ["*"],
85+
"privileges": ["read"],
86+
"allow_restricted_indices": false
87+
},
88+
{
89+
"names": ["*"],
90+
"privileges": ["read_failure_store"],
91+
"allow_restricted_indices": false
92+
}],
93+
"applications": [],
94+
"run_as": []
95+
}""")));
96+
}
97+
98+
private static Map<String, Object> mapFromJson(String json) {
99+
return XContentHelper.convertToMap(JsonXContent.jsonXContent, json, false);
100+
}
101+
}

x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/DeprecationRoleDescriptorConsumer.java

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -179,27 +179,34 @@ private void logDeprecatedPermission(RoleDescriptor roleDescriptor) {
179179
}
180180
}
181181
// compute privileges Automaton for each alias and for each of the indices it points to
182-
final Map<String, Automaton> indexAutomatonMap = new HashMap<>();
182+
final Map<String, Set<IndexPrivilege>> indexPrivilegeMap = new HashMap<>();
183183
for (Map.Entry<String, Set<String>> privilegesByAlias : privilegesByAliasMap.entrySet()) {
184184
final String aliasName = privilegesByAlias.getKey();
185185
final Set<String> aliasPrivilegeNames = privilegesByAlias.getValue();
186-
final Automaton aliasPrivilegeAutomaton = IndexPrivilege.getWithSingleSelectorAccess(aliasPrivilegeNames).getAutomaton();
186+
final Set<IndexPrivilege> aliasPrivileges = IndexPrivilege.splitBySelectorAccess(aliasPrivilegeNames);
187187
final SortedSet<String> inferiorIndexNames = new TreeSet<>();
188-
// check if the alias grants superiors privileges than the indices it points to
189-
for (Index index : aliasOrIndexMap.get(aliasName).getIndices()) {
190-
final Set<String> indexPrivileges = privilegesByIndexMap.get(index.getName());
191-
// null iff the index does not have *any* privilege
192-
if (indexPrivileges != null) {
193-
// compute automaton once per index no matter how many times it is pointed to
194-
final Automaton indexPrivilegeAutomaton = indexAutomatonMap.computeIfAbsent(
195-
index.getName(),
196-
i -> IndexPrivilege.getWithSingleSelectorAccess(indexPrivileges).getAutomaton()
197-
);
198-
if (false == Automatons.subsetOf(indexPrivilegeAutomaton, aliasPrivilegeAutomaton)) {
188+
for (var aliasPrivilege : aliasPrivileges) {
189+
final Automaton aliasPrivilegeAutomaton = aliasPrivilege.getAutomaton();
190+
// check if the alias grants superiors privileges than the indices it points to
191+
for (Index index : aliasOrIndexMap.get(aliasName).getIndices()) {
192+
final Set<String> indexPrivileges = privilegesByIndexMap.get(index.getName());
193+
// null iff the index does not have *any* privilege
194+
if (indexPrivileges != null) {
195+
// compute automaton once per index no matter how many times it is pointed to
196+
final Set<IndexPrivilege> indexPrivilegeSet = indexPrivilegeMap.computeIfAbsent(
197+
index.getName(),
198+
i -> IndexPrivilege.splitBySelectorAccess(indexPrivileges)
199+
);
200+
for (var indexPrivilege : indexPrivilegeSet) {
201+
// TODO still not quite right
202+
if (indexPrivilege.getSelectorPredicate() == aliasPrivilege.getSelectorPredicate()
203+
&& false == Automatons.subsetOf(indexPrivilege.getAutomaton(), aliasPrivilegeAutomaton)) {
204+
inferiorIndexNames.add(index.getName());
205+
}
206+
}
207+
} else {
199208
inferiorIndexNames.add(index.getName());
200209
}
201-
} else {
202-
inferiorIndexNames.add(index.getName());
203210
}
204211
}
205212
// log inferior indices for this role, for this alias

0 commit comments

Comments
 (0)