Skip to content

Commit adc6d69

Browse files
author
Yogesh Gaikwad
committed
change manage own api cluster privielge
1 parent 7db504c commit adc6d69

File tree

3 files changed

+111
-94
lines changed

3 files changed

+111
-94
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,11 +152,11 @@ public interface PermissionCheck {
152152
}
153153

154154
// Automaton based permission check
155-
private static class AutomatonPermissionCheck implements PermissionCheck {
155+
public static class AutomatonPermissionCheck implements PermissionCheck {
156156
private final Automaton automaton;
157157
private final Predicate<String> actionPredicate;
158158

159-
AutomatonPermissionCheck(final Automaton automaton) {
159+
public AutomatonPermissionCheck(final Automaton automaton) {
160160
this.automaton = automaton;
161161
this.actionPredicate = Automatons.predicate(automaton);
162162
}

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

Lines changed: 60 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -17,61 +17,14 @@
1717
import org.elasticsearch.xpack.core.security.authz.permission.ClusterPermission;
1818
import org.elasticsearch.xpack.core.security.support.Automatons;
1919

20-
import java.util.function.BiPredicate;
21-
import java.util.function.Predicate;
22-
2320
/**
2421
* Named cluster privilege for managing API keys owned by the current authenticated user.
2522
*/
2623
public class ManageOwnApiKeyClusterPrivilege implements NamedClusterPrivilege {
2724
public static final ManageOwnApiKeyClusterPrivilege INSTANCE = new ManageOwnApiKeyClusterPrivilege();
28-
private static final Predicate<String> ACTION_PREDICATE = Automatons.predicate("cluster:admin/xpack/security/api_key/*");
2925
private static final String PRIVILEGE_NAME = "manage_own_api_key";
30-
private final BiPredicate<TransportRequest, Authentication> requestAuthnPredicate;
3126

3227
private ManageOwnApiKeyClusterPrivilege() {
33-
this.requestAuthnPredicate = (request, authentication) -> {
34-
if (request instanceof CreateApiKeyRequest) {
35-
return true;
36-
} else if (request instanceof GetApiKeyRequest) {
37-
final GetApiKeyRequest getApiKeyRequest = (GetApiKeyRequest) request;
38-
return checkIfUserIsOwnerOfApiKeys(authentication, getApiKeyRequest.getApiKeyId(), getApiKeyRequest.getUserName(),
39-
getApiKeyRequest.getRealmName());
40-
} else if (request instanceof InvalidateApiKeyRequest) {
41-
final InvalidateApiKeyRequest invalidateApiKeyRequest = (InvalidateApiKeyRequest) request;
42-
return checkIfUserIsOwnerOfApiKeys(authentication, invalidateApiKeyRequest.getId(), invalidateApiKeyRequest.getUserName(),
43-
invalidateApiKeyRequest.getRealmName());
44-
}
45-
return false;
46-
};
47-
}
48-
49-
private boolean checkIfUserIsOwnerOfApiKeys(Authentication authentication, String apiKeyId, String username, String realmName) {
50-
if (isCurrentAuthenticationUsingSameApiKeyIdFromRequest(authentication, apiKeyId)) {
51-
return true;
52-
} else {
53-
/*
54-
* TODO bizybot we need to think on how we can propagate appropriate error message to the end user when username, realm name
55-
* is missing. This is similar to the problem of propagating right error messages in case of access denied.
56-
*/
57-
String authenticatedUserPrincipal = authentication.getUser().principal();
58-
String authenticatedUserRealm = authentication.getAuthenticatedBy().getName();
59-
if (Strings.hasText(username) && Strings.hasText(realmName)) {
60-
return username.equals(authenticatedUserPrincipal) && realmName.equals(authenticatedUserRealm);
61-
}
62-
}
63-
return false;
64-
}
65-
66-
private boolean isCurrentAuthenticationUsingSameApiKeyIdFromRequest(Authentication authentication, String apiKeyId) {
67-
if (authentication.getAuthenticatedBy().getType().equals("_es_api_key")) {
68-
// API key id from authentication must match the id from request
69-
String authenticatedApiKeyId = (String) authentication.getMetadata().get("_security_api_key_id");
70-
if (Strings.hasText(apiKeyId)) {
71-
return apiKeyId.equals(authenticatedApiKeyId);
72-
}
73-
}
74-
return false;
7528
}
7629

7730
@Override
@@ -81,6 +34,64 @@ public String name() {
8134

8235
@Override
8336
public ClusterPermission.Builder buildPermission(ClusterPermission.Builder builder) {
84-
return builder.add(this, ACTION_PREDICATE, requestAuthnPredicate);
37+
return builder.add(this, ManageOwnClusterPermissionCheck.INSTANCE);
38+
}
39+
40+
private static final class ManageOwnClusterPermissionCheck extends ClusterPermission.AutomatonPermissionCheck {
41+
public static final ManageOwnClusterPermissionCheck INSTANCE = new ManageOwnClusterPermissionCheck();
42+
private ManageOwnClusterPermissionCheck() {
43+
super(Automatons.patterns("cluster:admin/xpack/security/api_key/*"));
44+
}
45+
46+
@Override
47+
public boolean check(final String action, final TransportRequest request, final Authentication authentication) {
48+
if (super.check(action, request, authentication)) {
49+
if (request instanceof CreateApiKeyRequest) {
50+
return true;
51+
} else if (request instanceof GetApiKeyRequest) {
52+
final GetApiKeyRequest getApiKeyRequest = (GetApiKeyRequest) request;
53+
return checkIfUserIsOwnerOfApiKeys(authentication, getApiKeyRequest.getApiKeyId(), getApiKeyRequest.getUserName(),
54+
getApiKeyRequest.getRealmName());
55+
} else if (request instanceof InvalidateApiKeyRequest) {
56+
final InvalidateApiKeyRequest invalidateApiKeyRequest = (InvalidateApiKeyRequest) request;
57+
return checkIfUserIsOwnerOfApiKeys(authentication, invalidateApiKeyRequest.getId(), invalidateApiKeyRequest.getUserName(),
58+
invalidateApiKeyRequest.getRealmName());
59+
}
60+
}
61+
return false;
62+
}
63+
64+
@Override
65+
public boolean implies(final ClusterPermission.PermissionCheck permissionCheck) {
66+
return super.implies(permissionCheck);
67+
}
68+
69+
private boolean checkIfUserIsOwnerOfApiKeys(Authentication authentication, String apiKeyId, String username, String realmName) {
70+
if (isCurrentAuthenticationUsingSameApiKeyIdFromRequest(authentication, apiKeyId)) {
71+
return true;
72+
} else {
73+
/*
74+
* TODO bizybot we need to think on how we can propagate appropriate error message to the end user when username, realm name
75+
* is missing. This is similar to the problem of propagating right error messages in case of access denied.
76+
*/
77+
String authenticatedUserPrincipal = authentication.getUser().principal();
78+
String authenticatedUserRealm = authentication.getAuthenticatedBy().getName();
79+
if (Strings.hasText(username) && Strings.hasText(realmName)) {
80+
return username.equals(authenticatedUserPrincipal) && realmName.equals(authenticatedUserRealm);
81+
}
82+
}
83+
return false;
84+
}
85+
86+
private boolean isCurrentAuthenticationUsingSameApiKeyIdFromRequest(Authentication authentication, String apiKeyId) {
87+
if (authentication.getAuthenticatedBy().getType().equals("_es_api_key")) {
88+
// API key id from authentication must match the id from request
89+
String authenticatedApiKeyId = (String) authentication.getMetadata().get("_security_api_key_id");
90+
if (Strings.hasText(apiKeyId)) {
91+
return apiKeyId.equals(authenticatedApiKeyId);
92+
}
93+
}
94+
return false;
95+
}
8596
}
86-
}
97+
}

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

Lines changed: 49 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -23,55 +23,61 @@
2323

2424
public class ManageOwnApiKeyClusterPrivilegeTests extends ESTestCase {
2525

26-
public void testActionRequestAuthenticationBasedPredicateWhenAuthenticatingWithApiKey() {
26+
public void testAuthenticationWithApiKeyAllowsAccessToApiKeyActionsWhenItIsOwner() {
2727
final ClusterPermission clusterPermission =
2828
ManageOwnApiKeyClusterPrivilege.INSTANCE.buildPermission(ClusterPermission.builder()).build();
29-
{
30-
final String apiKeyId = randomAlphaOfLengthBetween(4, 7);
31-
final Authentication authentication = createMockAuthentication("_es_api_key", "_es_api_key",
32-
Map.of("_security_api_key_id", apiKeyId));
33-
final TransportRequest request = randomFrom(GetApiKeyRequest.usingApiKeyId(apiKeyId, randomBoolean()),
34-
InvalidateApiKeyRequest.usingApiKeyId(apiKeyId, randomBoolean()));
35-
36-
assertTrue(clusterPermission.check("cluster:admin/xpack/security/api_key/get", request, authentication));
37-
assertTrue(clusterPermission.check("cluster:admin/xpack/security/api_key/invalidate", request, authentication));
38-
assertFalse(clusterPermission.check("cluster:admin/something", request, authentication));
39-
}
40-
{
41-
final String apiKeyId = randomAlphaOfLengthBetween(4, 7);
42-
final Authentication authentication = createMockAuthentication("_es_api_key", "_es_api_key",
43-
Map.of("_security_api_key_id", randomAlphaOfLength(7)));
44-
final TransportRequest request = randomFrom(GetApiKeyRequest.usingApiKeyId(apiKeyId, randomBoolean()),
45-
InvalidateApiKeyRequest.usingApiKeyId(apiKeyId, randomBoolean()));
46-
47-
assertFalse(clusterPermission.check("cluster:admin/xpack/security/api_key/get", request, authentication));
48-
assertFalse(clusterPermission.check("cluster:admin/xpack/security/api_key/invalidate", request, authentication));
49-
}
29+
30+
final String apiKeyId = randomAlphaOfLengthBetween(4, 7);
31+
final Authentication authentication = createMockAuthentication("_es_api_key", "_es_api_key",
32+
Map.of("_security_api_key_id", apiKeyId));
33+
final TransportRequest request = randomFrom(GetApiKeyRequest.usingApiKeyId(apiKeyId, randomBoolean()),
34+
InvalidateApiKeyRequest.usingApiKeyId(apiKeyId, randomBoolean()));
35+
36+
assertTrue(clusterPermission.check("cluster:admin/xpack/security/api_key/get", request, authentication));
37+
assertTrue(clusterPermission.check("cluster:admin/xpack/security/api_key/invalidate", request, authentication));
38+
assertFalse(clusterPermission.check("cluster:admin/something", request, authentication));
39+
}
40+
41+
public void testAuthenticationWithApiKeyDeniesAccessToApiKeyActionsWhenItIsNotOwner() {
42+
final ClusterPermission clusterPermission =
43+
ManageOwnApiKeyClusterPrivilege.INSTANCE.buildPermission(ClusterPermission.builder()).build();
44+
45+
final String apiKeyId = randomAlphaOfLengthBetween(4, 7);
46+
final Authentication authentication = createMockAuthentication("_es_api_key", "_es_api_key",
47+
Map.of("_security_api_key_id", randomAlphaOfLength(7)));
48+
final TransportRequest request = randomFrom(GetApiKeyRequest.usingApiKeyId(apiKeyId, randomBoolean()),
49+
InvalidateApiKeyRequest.usingApiKeyId(apiKeyId, randomBoolean()));
50+
51+
assertFalse(clusterPermission.check("cluster:admin/xpack/security/api_key/get", request, authentication));
52+
assertFalse(clusterPermission.check("cluster:admin/xpack/security/api_key/invalidate", request, authentication));
5053
}
5154

52-
public void testActionRequestAuthenticationBasedPredicateWhenRequestContainsUsernameAndRealmName() {
55+
public void testAuthenticationWithUserAllowsAccessToApiKeyActionsWhenItIsOwner() {
5356
final ClusterPermission clusterPermission =
5457
ManageOwnApiKeyClusterPrivilege.INSTANCE.buildPermission(ClusterPermission.builder()).build();
55-
{
56-
final Authentication authentication = createMockAuthentication("realm1", "native", Map.of());
57-
final TransportRequest request = randomFrom(GetApiKeyRequest.usingRealmAndUserName("realm1", "joe"),
58-
InvalidateApiKeyRequest.usingRealmAndUserName("realm1", "joe"));
59-
60-
assertTrue(clusterPermission.check("cluster:admin/xpack/security/api_key/get", request, authentication));
61-
assertTrue(clusterPermission.check("cluster:admin/xpack/security/api_key/invalidate", request, authentication));
62-
assertFalse(clusterPermission.check("cluster:admin/something", request, authentication));
63-
}
64-
{
65-
final Authentication authentication = createMockAuthentication("realm1", "native", Map.of());
66-
final TransportRequest request = randomFrom(
67-
GetApiKeyRequest.usingRealmAndUserName("realm1", randomAlphaOfLength(7)),
68-
GetApiKeyRequest.usingRealmAndUserName(randomAlphaOfLength(5), "joe"),
69-
InvalidateApiKeyRequest.usingRealmAndUserName("realm1", randomAlphaOfLength(7)),
70-
InvalidateApiKeyRequest.usingRealmAndUserName(randomAlphaOfLength(5), "joe"));
71-
72-
assertFalse(clusterPermission.check("cluster:admin/xpack/security/api_key/get", request, authentication));
73-
assertFalse(clusterPermission.check("cluster:admin/xpack/security/api_key/invalidate", request, authentication));
74-
}
58+
59+
final Authentication authentication = createMockAuthentication("realm1", "native", Map.of());
60+
final TransportRequest request = randomFrom(GetApiKeyRequest.usingRealmAndUserName("realm1", "joe"),
61+
InvalidateApiKeyRequest.usingRealmAndUserName("realm1", "joe"));
62+
63+
assertTrue(clusterPermission.check("cluster:admin/xpack/security/api_key/get", request, authentication));
64+
assertTrue(clusterPermission.check("cluster:admin/xpack/security/api_key/invalidate", request, authentication));
65+
assertFalse(clusterPermission.check("cluster:admin/something", request, authentication));
66+
}
67+
68+
public void testAuthenticationWithUserAllowsAccessToApiKeyActionsWhenItIsNotOwner() {
69+
final ClusterPermission clusterPermission =
70+
ManageOwnApiKeyClusterPrivilege.INSTANCE.buildPermission(ClusterPermission.builder()).build();
71+
72+
final Authentication authentication = createMockAuthentication("realm1", "native", Map.of());
73+
final TransportRequest request = randomFrom(
74+
GetApiKeyRequest.usingRealmAndUserName("realm1", randomAlphaOfLength(7)),
75+
GetApiKeyRequest.usingRealmAndUserName(randomAlphaOfLength(5), "joe"),
76+
InvalidateApiKeyRequest.usingRealmAndUserName("realm1", randomAlphaOfLength(7)),
77+
InvalidateApiKeyRequest.usingRealmAndUserName(randomAlphaOfLength(5), "joe"));
78+
79+
assertFalse(clusterPermission.check("cluster:admin/xpack/security/api_key/get", request, authentication));
80+
assertFalse(clusterPermission.check("cluster:admin/xpack/security/api_key/invalidate", request, authentication));
7581
}
7682

7783
private Authentication createMockAuthentication(String realmName, String realmType, Map<String, Object> metadata) {

0 commit comments

Comments
 (0)