Skip to content

Commit 7f195f1

Browse files
committed
Tests
1 parent 65dd807 commit 7f195f1

File tree

3 files changed

+160
-11
lines changed

3 files changed

+160
-11
lines changed

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

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,53 @@ public void testGetUserPrivileges() throws IOException {
211211
"applications": [],
212212
"run_as": []
213213
}""");
214+
215+
upsertRole("""
216+
{
217+
"cluster": ["all"],
218+
"indices": [
219+
{
220+
"names": ["*", "idx"],
221+
"privileges": ["read", "manage"],
222+
"allow_restricted_indices": false
223+
},
224+
{
225+
"names": ["idx", "*"],
226+
"privileges": ["manage_data_stream_lifecycle"],
227+
"allow_restricted_indices": false
228+
},
229+
{
230+
"names": ["*", "idx"],
231+
"privileges": ["write"],
232+
"allow_restricted_indices": true
233+
},
234+
{
235+
"names": ["idx", "*"],
236+
"privileges": ["manage"],
237+
"allow_restricted_indices": true
238+
}
239+
]
240+
}
241+
""", "role");
242+
expectUserPrivilegesResponse("""
243+
{
244+
"cluster": ["all"],
245+
"global": [],
246+
"indices": [
247+
{
248+
"names": ["*", "idx"],
249+
"privileges": ["manage", "manage_data_stream_lifecycle", "read"],
250+
"allow_restricted_indices": false
251+
},
252+
{
253+
"names": ["*", "idx"],
254+
"privileges": ["manage", "write"],
255+
"allow_restricted_indices": true
256+
}
257+
],
258+
"applications": [],
259+
"run_as": []
260+
}""");
214261
}
215262

216263
public void testHasPrivileges() throws IOException {

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

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -794,7 +794,7 @@ static GetUserPrivilegesResponse buildUserPrivilegesResponseObject(Role userRole
794794
}
795795
}
796796

797-
final LinkedHashSet<GetUserPrivilegesResponse.Indices> indices = new LinkedHashSet<>();
797+
final Set<GetUserPrivilegesResponse.Indices> indices = new LinkedHashSet<>();
798798
for (IndicesPermission.Group group : userRole.indices().groups()) {
799799
indices.add(toIndices(group));
800800
}
@@ -843,27 +843,38 @@ static GetUserPrivilegesResponse buildUserPrivilegesResponseObject(Role userRole
843843
);
844844
}
845845

846-
private static LinkedHashSet<GetUserPrivilegesResponse.Indices> combineIndices(
847-
LinkedHashSet<GetUserPrivilegesResponse.Indices> indices
848-
) {
849-
final LinkedHashMap<Tuple<Boolean, Set<String>>, GetUserPrivilegesResponse.Indices> combinedIndices = new LinkedHashMap<>();
846+
/**
847+
* Due to selector-processing during role building
848+
* (see {@link org.elasticsearch.xpack.core.security.authz.privilege.IndexPrivilege#resolveBySelectorAccess(Set)}),
849+
* it is possible that multiple index groups with the same indices exist with different privilege sets. To provide a cleaner response,
850+
* this method combines them into one group.
851+
*/
852+
private static Set<GetUserPrivilegesResponse.Indices> combineIndices(Set<GetUserPrivilegesResponse.Indices> indices) {
853+
final Map<Tuple<Boolean, Set<String>>, GetUserPrivilegesResponse.Indices> combinedIndices = new LinkedHashMap<>();
850854
for (GetUserPrivilegesResponse.Indices index : indices) {
851855
final GetUserPrivilegesResponse.Indices existing = combinedIndices.get(
852856
new Tuple<>(index.allowRestrictedIndices(), index.getIndices())
853857
);
854858
if (existing == null) {
855859
combinedIndices.put(new Tuple<>(index.allowRestrictedIndices(), index.getIndices()), index);
856860
} else {
857-
Set<String> combined = new LinkedHashSet<>(existing.getPrivileges());
858-
combined.addAll(index.getPrivileges());
859-
assert existing.allowRestrictedIndices() == index.allowRestrictedIndices();
860-
assert Objects.equals(existing.getFieldSecurity(), index.getFieldSecurity());
861-
assert Objects.equals(existing.getQueries(), index.getQueries());
861+
Set<String> combinedPrivileges = new HashSet<>(existing.getPrivileges());
862+
combinedPrivileges.addAll(index.getPrivileges());
863+
boolean flsDlsMatch = Objects.equals(existing.getFieldSecurity(), index.getFieldSecurity())
864+
&& Objects.equals(existing.getQueries(), index.getQueries());
865+
assert existing.getIndices().equals(index.getIndices())
866+
&& existing.allowRestrictedIndices() == index.allowRestrictedIndices()
867+
// due to collation & selector resolution code, fls and dls definitions are always the same if the indices match
868+
&& flsDlsMatch;
869+
if (false == flsDlsMatch) {
870+
// if the above invariant is violated, due to a bug, bail and return original indices (these will still be correct)
871+
return indices;
872+
}
862873
combinedIndices.put(
863874
new Tuple<>(index.allowRestrictedIndices(), index.getIndices()),
864875
new GetUserPrivilegesResponse.Indices(
865876
index.getIndices(),
866-
combined,
877+
combinedPrivileges,
867878
index.getFieldSecurity(),
868879
index.getQueries(),
869880
index.allowRestrictedIndices()

x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/RBACEngineTests.java

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1415,6 +1415,82 @@ public void testBuildUserPrivilegeResponse() {
14151415
}
14161416
}
14171417

1418+
public void testBuildUserPrivilegeResponseCombinesIndexPrivileges() {
1419+
final BytesArray query = new BytesArray("""
1420+
{"term":{"public":true}}""");
1421+
final Role role = Role.builder(RESTRICTED_INDICES, "test", "role")
1422+
.add(IndexPrivilegeTests.resolvePrivilegeAndAssertSingleton(Sets.newHashSet("read", "write")), "index-1")
1423+
.add(IndexPrivilege.ALL, "index-2")
1424+
.add(
1425+
new FieldPermissions(new FieldPermissionsDefinition(new String[] { "public.*" }, new String[0])),
1426+
Collections.singleton(query),
1427+
IndexPrivilege.MANAGE,
1428+
true,
1429+
"index-1",
1430+
"index-2"
1431+
)
1432+
.add(
1433+
new FieldPermissions(new FieldPermissionsDefinition(new String[] { "public.*" }, new String[0])),
1434+
Collections.singleton(query),
1435+
IndexPrivilegeTests.resolvePrivilegeAndAssertSingleton(Sets.newHashSet("read", "write")),
1436+
true,
1437+
"index-2",
1438+
"index-1"
1439+
)
1440+
.add(
1441+
new FieldPermissions(new FieldPermissionsDefinition(new String[] { "public.*" }, new String[0])),
1442+
Collections.singleton(query),
1443+
IndexPrivilegeTests.resolvePrivilegeAndAssertSingleton(Sets.newHashSet("read_failure_store", "manage_failure_store")),
1444+
true,
1445+
"index-2",
1446+
"index-1"
1447+
)
1448+
.add(
1449+
FieldPermissions.DEFAULT,
1450+
null,
1451+
IndexPrivilegeTests.resolvePrivilegeAndAssertSingleton(Sets.newHashSet("read_failure_store")),
1452+
false,
1453+
"index-2",
1454+
"index-1"
1455+
)
1456+
.build();
1457+
1458+
final GetUserPrivilegesResponse response = RBACEngine.buildUserPrivilegesResponseObject(role);
1459+
1460+
final GetUserPrivilegesResponse.Indices index1 = findIndexPrivilege(response.getIndexPrivileges(), Set.of("index-1"), false);
1461+
assertThat(index1.getIndices(), containsInAnyOrder("index-1"));
1462+
assertThat(index1.getPrivileges(), containsInAnyOrder("read", "write"));
1463+
assertThat(index1.getFieldSecurity(), emptyIterable());
1464+
assertThat(index1.getQueries(), emptyIterable());
1465+
1466+
final GetUserPrivilegesResponse.Indices index2 = findIndexPrivilege(response.getIndexPrivileges(), Set.of("index-2"), false);
1467+
assertThat(index2.getIndices(), containsInAnyOrder("index-2"));
1468+
assertThat(index2.getPrivileges(), containsInAnyOrder("all"));
1469+
assertThat(index2.getFieldSecurity(), emptyIterable());
1470+
assertThat(index2.getQueries(), emptyIterable());
1471+
1472+
Set<GetUserPrivilegesResponse.Indices> actualIndexPrivileges = response.getIndexPrivileges();
1473+
assertThat(actualIndexPrivileges, iterableWithSize(4));
1474+
final GetUserPrivilegesResponse.Indices index1And2 = findIndexPrivilege(actualIndexPrivileges, Set.of("index-1", "index-2"), true);
1475+
assertThat(index1And2.getIndices(), containsInAnyOrder("index-1", "index-2"));
1476+
assertThat(index1And2.getPrivileges(), containsInAnyOrder("read", "write", "read_failure_store", "manage_failure_store", "manage"));
1477+
assertThat(
1478+
index1And2.getFieldSecurity(),
1479+
containsInAnyOrder(new FieldPermissionsDefinition.FieldGrantExcludeGroup(new String[] { "public.*" }, new String[0]))
1480+
);
1481+
assertThat(index1And2.getQueries(), containsInAnyOrder(query));
1482+
1483+
final GetUserPrivilegesResponse.Indices index1And2NotRestricted = findIndexPrivilege(
1484+
actualIndexPrivileges,
1485+
Set.of("index-1", "index-2"),
1486+
false
1487+
);
1488+
assertThat(index1And2NotRestricted.getIndices(), containsInAnyOrder("index-1", "index-2"));
1489+
assertThat(index1And2NotRestricted.getPrivileges(), containsInAnyOrder("read_failure_store"));
1490+
assertThat(index1And2NotRestricted.getFieldSecurity(), emptyIterable());
1491+
assertThat(index1And2NotRestricted.getQueries(), emptyIterable());
1492+
}
1493+
14181494
public void testBackingIndicesAreIncludedForAuthorizedDataStreams() {
14191495
final String dataStreamName = "my_data_stream";
14201496
User user = new User(randomAlphaOfLengthBetween(4, 12));
@@ -2017,6 +2093,21 @@ private static RequestInfo createRequestInfo(TransportRequest request, String ac
20172093
);
20182094
}
20192095

2096+
private GetUserPrivilegesResponse.Indices findIndexPrivilege(
2097+
Set<GetUserPrivilegesResponse.Indices> indices,
2098+
Set<String> indexNames,
2099+
boolean allowRestrictedIndices
2100+
) {
2101+
return indices.stream()
2102+
.filter(
2103+
i -> i.allowRestrictedIndices() == allowRestrictedIndices
2104+
&& i.getIndices().containsAll(indexNames)
2105+
&& indexNames.containsAll(i.getIndices())
2106+
)
2107+
.findFirst()
2108+
.get();
2109+
}
2110+
20202111
private GetUserPrivilegesResponse.Indices findIndexPrivilege(Set<GetUserPrivilegesResponse.Indices> indices, String name) {
20212112
return indices.stream().filter(i -> i.getIndices().contains(name)).findFirst().get();
20222113
}

0 commit comments

Comments
 (0)