Skip to content

Commit 6087767

Browse files
authored
Require that all app privileges have actions (#32272)
The javadoc and validation for ApplicationPrivileges supports the idea that a privilege could have no actions. However, in that case every privilege that had no actions grants every other action-less privilege within the same action, including the NONE privilege. This commit makes the following changes: - It is not possible to PUT a privilege without any actions - A permission with no actions, never grants another privilege even if that privilege is also a zero-action privilege (which, ideally would never exist, but can occur through missing privileges or index manipulation).
1 parent 1c1240d commit 6087767

File tree

6 files changed

+34
-1
lines changed

6 files changed

+34
-1
lines changed

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/privilege/PutPrivilegesRequest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ public ActionRequestValidationException validate() {
5050
} catch (IllegalArgumentException e) {
5151
validationException = addValidationError(e.getMessage(), validationException);
5252
}
53+
if (privilege.getActions().isEmpty()) {
54+
validationException = addValidationError("Application privileges must have at least one action", validationException);
55+
}
5356
for (String action : privilege.getActions()) {
5457
if (action.indexOf('/') == -1 && action.indexOf('*') == -1 && action.indexOf(':') == -1) {
5558
validationException = addValidationError("action [" + action + "] must contain one of [ '/' , '*' , ':' ]",

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/permission/ApplicationPermission.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ private PermissionEntry(ApplicationPrivilege privilege, Automaton resources) {
9797

9898
private boolean grants(ApplicationPrivilege other, Automaton resource) {
9999
return this.application.test(other.getApplication())
100+
&& Operations.isEmpty(privilege.getAutomaton()) == false
100101
&& Operations.subsetOf(other.getAutomaton(), privilege.getAutomaton())
101102
&& Operations.subsetOf(resource, this.resources);
102103
}

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/ApplicationPrivilege.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
/**
2222
* An application privilege has an application name (e.g. {@code "my-app"}) that identifies an application (that exists
23-
* outside of elasticsearch), a privilege name (e.g. {@code "admin}) that is meaningful to that application, and zero or
23+
* outside of elasticsearch), a privilege name (e.g. {@code "admin}) that is meaningful to that application, and one or
2424
* more "action patterns" (e.g {@code "admin/user/*", "admin/team/*"}).
2525
* Action patterns must contain at least one special character from ({@code /}, {@code :}, {@code *}) to distinguish them
2626
* from privilege names.

x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/action/privilege/PutPrivilegesRequestTests.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ public void testValidation() {
5757
assertValidationFailure(request(spaceName), "Application privilege names must match");
5858
assertValidationFailure(request(numericName), "Application privilege names must match");
5959

60+
// no actions
61+
final ApplicationPrivilegeDescriptor nothing = descriptor("*", "nothing");
62+
assertValidationFailure(request(nothing), "Application privileges must have at least one action");
63+
6064
// reserved metadata
6165
final ApplicationPrivilegeDescriptor reservedMetadata = new ApplicationPrivilegeDescriptor("app", "all",
6266
Collections.emptySet(), Collections.singletonMap("_notAllowed", true)

x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/permission/ApplicationPermissionTests.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import org.elasticsearch.xpack.core.security.authz.privilege.ApplicationPrivilegeDescriptor;
1313

1414
import java.util.ArrayList;
15+
import java.util.Arrays;
1516
import java.util.Collections;
1617
import java.util.List;
1718

@@ -23,6 +24,7 @@ public class ApplicationPermissionTests extends ESTestCase {
2324
private List<ApplicationPrivilegeDescriptor> store = new ArrayList<>();
2425

2526
private ApplicationPrivilege app1All = storePrivilege("app1", "all", "*");
27+
private ApplicationPrivilege app1Empty = storePrivilege("app1", "empty");
2628
private ApplicationPrivilege app1Read = storePrivilege("app1", "read", "read/*");
2729
private ApplicationPrivilege app1Write = storePrivilege("app1", "write", "write/*");
2830
private ApplicationPrivilege app1Delete = storePrivilege("app1", "delete", "write/delete");
@@ -47,6 +49,15 @@ public void testCheckSimplePermission() {
4749
assertThat(hasPermission.grants(app1All, "foo"), equalTo(false));
4850
}
4951

52+
public void testNonePermission() {
53+
final ApplicationPermission hasPermission = buildPermission(ApplicationPrivilege.NONE.apply("app1"), "*");
54+
for (ApplicationPrivilege privilege : Arrays.asList(app1All, app1Empty, app1Create, app1Delete, app1Read, app1Write, app2Read)) {
55+
assertThat("Privilege " + privilege + " on *", hasPermission.grants(privilege, "*"), equalTo(false));
56+
final String resource = randomAlphaOfLengthBetween(1, 6);
57+
assertThat("Privilege " + privilege + " on " + resource, hasPermission.grants(privilege, resource), equalTo(false));
58+
}
59+
}
60+
5061
public void testResourceMatching() {
5162
final ApplicationPermission hasPermission = buildPermission(app1All, "dashboard/*", "audit/*", "user/12345");
5263

x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/privilege/ApplicationPrivilegeTests.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,20 @@ public void testValidationOfPrivilegeName() {
8686
}
8787
}
8888

89+
public void testNonePrivilege() {
90+
final ApplicationPrivilege none = ApplicationPrivilege.NONE.apply("super-mega-app");
91+
CharacterRunAutomaton run = new CharacterRunAutomaton(none.getAutomaton());
92+
for (int i = randomIntBetween(5, 10); i > 0; i--) {
93+
final String action;
94+
if (randomBoolean()) {
95+
action = randomAlphaOfLengthBetween(3, 12);
96+
} else {
97+
action = randomAlphaOfLengthBetween(3, 6) + randomFrom(":", "/") + randomAlphaOfLengthBetween(3, 8);
98+
}
99+
assertFalse("NONE should not grant " + action, run.run(action));
100+
}
101+
}
102+
89103
public void testGetPrivilegeByName() {
90104
final ApplicationPrivilegeDescriptor descriptor = descriptor("my-app", "read", "data:read/*", "action:login");
91105
final ApplicationPrivilegeDescriptor myWrite = descriptor("my-app", "write", "data:write/*", "action:login");

0 commit comments

Comments
 (0)