Skip to content

Commit e68b0c0

Browse files
committed
Add permission
1 parent 20b2038 commit e68b0c0

File tree

8 files changed

+77
-10
lines changed

8 files changed

+77
-10
lines changed

docs/reference/ccr/apis/follow/post-forget-follower.asciidoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ POST /<leader_index>/_ccr/forget_follower
111111

112112
==== Authorization
113113

114-
If the {es} {security-features} are enabled, you must have `manage_follow_index`
115-
index privileges for the follower index. For more information, see
114+
If the {es} {security-features} are enabled, you must have `manage_leader_index`
115+
index privileges for the leader index. For more information, see
116116
{stack-ov}/security-privileges.html[Security privileges].
117117

118118
==== Example

x-pack/plugin/ccr/qa/security/follower-roles.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ ccruser:
22
cluster:
33
- manage_ccr
44
indices:
5-
- names: [ 'allowed-index', 'logs-eu-*' ]
5+
- names: [ 'allowed-index', 'forget-follower', 'logs-eu-*' ]
66
privileges:
77
- monitor
88
- read

x-pack/plugin/ccr/qa/security/leader-roles.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ ccruser:
22
cluster:
33
- read_ccr
44
indices:
5-
- names: [ 'allowed-index', 'logs-eu-*' ]
5+
- names: [ 'allowed-index', 'forget-leader', 'logs-eu-*' ]
66
privileges:
77
- monitor
88
- read
9+
- manage_leader_index

x-pack/plugin/ccr/qa/security/src/test/java/org/elasticsearch/xpack/ccr/FollowIndexSecurityIT.java

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,27 @@
66
package org.elasticsearch.xpack.ccr;
77

88
import org.elasticsearch.client.Request;
9+
import org.elasticsearch.client.Response;
910
import org.elasticsearch.client.ResponseException;
1011
import org.elasticsearch.client.RestClient;
1112
import org.elasticsearch.common.Strings;
1213
import org.elasticsearch.common.settings.SecureString;
1314
import org.elasticsearch.common.settings.Settings;
1415
import org.elasticsearch.common.util.concurrent.ThreadContext;
1516
import org.elasticsearch.common.xcontent.support.XContentMapValues;
17+
import org.elasticsearch.test.rest.yaml.ObjectPath;
1618

19+
import java.io.IOException;
20+
import java.util.ArrayList;
1721
import java.util.List;
1822
import java.util.Map;
1923
import java.util.concurrent.TimeUnit;
2024

2125
import static org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
2226
import static org.hamcrest.Matchers.containsString;
27+
import static org.hamcrest.Matchers.empty;
2328
import static org.hamcrest.Matchers.equalTo;
29+
import static org.hamcrest.Matchers.hasSize;
2430
import static org.hamcrest.Matchers.is;
2531

2632
public class FollowIndexSecurityIT extends ESCCRRestTestCase {
@@ -176,4 +182,51 @@ public void testAutoFollowPatterns() throws Exception {
176182
pauseFollow(client(), allowedIndex);
177183
}
178184

185+
public void testForgetFollower() throws IOException {
186+
final String forgetLeader = "forget-leader";
187+
final String forgetFollower = "forget-follower";
188+
if ("leader".equals(targetCluster)) {
189+
logger.info("running against leader cluster");
190+
final Settings indexSettings = Settings.builder()
191+
.put("index.number_of_replicas", 0)
192+
.put("index.number_of_shards", 1)
193+
.put("index.soft_deletes.enabled", true)
194+
.build();
195+
createIndex(forgetLeader, indexSettings);
196+
} else {
197+
logger.info("running against follower cluster");
198+
followIndex(client(), "leader_cluster", forgetLeader, forgetFollower);
199+
200+
final Response response = client().performRequest(new Request("GET", "/" + forgetFollower + "/_stats"));
201+
final String followerIndexUUID = ObjectPath.createFromResponse(response).evaluate("indices." + forgetFollower + ".uuid");
202+
203+
assertOK(client().performRequest(new Request("POST", "/" + forgetFollower + "/_ccr/pause_follow")));
204+
205+
try (RestClient leaderClient = buildLeaderClient(restClientSettings())) {
206+
final Request request = new Request("POST", "/" + forgetLeader + "/_ccr/forget_follower");
207+
final String requestBody = "{" +
208+
"\"follower_cluster\":\"follow-cluster\"," +
209+
"\"follower_index\":\"" + forgetFollower + "\"," +
210+
"\"follower_index_uuid\":\"" + followerIndexUUID + "\"," +
211+
"\"leader_remote_cluster\":\"leader_cluster\"" +
212+
"}";
213+
request.setJsonEntity(requestBody);
214+
logger.info(requestBody);
215+
assertOK(leaderClient.performRequest(request));
216+
217+
final Request retentionLeasesRequest = new Request("GET", "/" + forgetLeader + "/_stats");
218+
retentionLeasesRequest.addParameter("level", "shards");
219+
final Response retentionLeasesResponse = leaderClient.performRequest(retentionLeasesRequest);
220+
final ArrayList<Object> shardsStats =
221+
ObjectPath.createFromResponse(retentionLeasesResponse).evaluate("indices." + forgetLeader + ".shards.0");
222+
assertThat(shardsStats, hasSize(1));
223+
@SuppressWarnings("unchecked") final Map<String, Object> shardStatsAsMap = (Map<String, Object>)shardsStats.get(0);
224+
@SuppressWarnings("unchecked") final Map<String, Object> retentionLeasesStats =
225+
(Map<String, Object>) shardStatsAsMap.get("retention_leases");
226+
@SuppressWarnings("unchecked") final ArrayList<Object> leases = (ArrayList<Object>)retentionLeasesStats.get("leases");
227+
assertThat(leases, empty());
228+
}
229+
}
230+
}
231+
179232
}

x-pack/plugin/ccr/qa/src/main/java/org/elasticsearch/xpack/ccr/ESCCRRestTestCase.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -255,16 +255,25 @@ protected RestClient buildLeaderClient() throws IOException {
255255
return buildClient(System.getProperty("tests.leader_host"));
256256
}
257257

258+
protected RestClient buildLeaderClient(final Settings settings) throws IOException {
259+
assert "leader".equals(targetCluster) == false;
260+
return buildClient(System.getProperty("tests.leader_host"), settings);
261+
}
262+
258263
protected RestClient buildMiddleClient() throws IOException {
259264
assert "middle".equals(targetCluster) == false;
260265
return buildClient(System.getProperty("tests.middle_host"));
261266
}
262267

263268
private RestClient buildClient(final String url) throws IOException {
269+
return buildClient(url, restAdminSettings());
270+
}
271+
272+
private RestClient buildClient(final String url, final Settings settings) throws IOException {
264273
int portSeparator = url.lastIndexOf(':');
265274
HttpHost httpHost = new HttpHost(url.substring(0, portSeparator),
266-
Integer.parseInt(url.substring(portSeparator + 1)), getProtocol());
267-
return buildClient(restAdminSettings(), new HttpHost[]{httpHost});
275+
Integer.parseInt(url.substring(portSeparator + 1)), getProtocol());
276+
return buildClient(settings, new HttpHost[]{httpHost});
268277
}
269278

270279
}

x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/action/TransportForgetFollowerAction.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public TransportForgetFollowerAction(
5656
final IndexNameExpressionResolver indexNameExpressionResolver,
5757
final IndicesService indicesService) {
5858
super(
59-
ForgetFollowerAction.ACTION_NAME,
59+
ForgetFollowerAction.NAME,
6060
Objects.requireNonNull(clusterService),
6161
Objects.requireNonNull(transportService),
6262
Objects.requireNonNull(actionFilters),

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/action/ForgetFollowerAction.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@
2121

2222
public class ForgetFollowerAction extends Action<BroadcastResponse> {
2323

24-
public static final String ACTION_NAME = "indices:admin/xpack/ccr/forget_follower";
24+
public static final String NAME = "indices:admin/xpack/ccr/forget_follower";
2525
public static final ForgetFollowerAction INSTANCE = new ForgetFollowerAction();
2626

2727
private ForgetFollowerAction() {
28-
super(ACTION_NAME);
28+
super(NAME);
2929
}
3030

3131
@Override
@@ -44,7 +44,7 @@ public static class Request extends BroadcastRequest<Request> {
4444
private static final ParseField FOLLOWER_INDEX_UUID = new ParseField("follower_index_uuid");
4545
private static final ParseField LEADER_REMOTE_CLUSTER = new ParseField("leader_remote_cluster");
4646

47-
private static final ObjectParser<String[], Void> PARSER = new ObjectParser<>(ACTION_NAME, () -> new String[4]);
47+
private static final ObjectParser<String[], Void> PARSER = new ObjectParser<>(NAME, () -> new String[4]);
4848

4949
static {
5050
PARSER.declareString((parameters, value) -> parameters[0] = value, FOLLOWER_CLUSTER);

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryAction;
2323
import org.elasticsearch.common.Strings;
2424
import org.elasticsearch.common.collect.MapBuilder;
25+
import org.elasticsearch.xpack.core.ccr.action.ForgetFollowerAction;
2526
import org.elasticsearch.xpack.core.ccr.action.PutFollowAction;
2627
import org.elasticsearch.xpack.core.ccr.action.UnfollowAction;
2728
import org.elasticsearch.xpack.core.indexlifecycle.action.ExplainLifecycleAction;
@@ -62,6 +63,7 @@ public final class IndexPrivilege extends Privilege {
6263
ExplainLifecycleAction.NAME);
6364
private static final Automaton MANAGE_FOLLOW_INDEX_AUTOMATON = patterns(PutFollowAction.NAME, UnfollowAction.NAME,
6465
CloseIndexAction.NAME + "*");
66+
private static final Automaton MANAGE_LEADER_INDEX_AUTOMATON = patterns(ForgetFollowerAction.NAME);
6567
private static final Automaton MANAGE_ILM_AUTOMATON = patterns("indices:admin/ilm/*");
6668

6769
public static final IndexPrivilege NONE = new IndexPrivilege("none", Automatons.EMPTY);
@@ -78,6 +80,7 @@ public final class IndexPrivilege extends Privilege {
7880
public static final IndexPrivilege CREATE_INDEX = new IndexPrivilege("create_index", CREATE_INDEX_AUTOMATON);
7981
public static final IndexPrivilege VIEW_METADATA = new IndexPrivilege("view_index_metadata", VIEW_METADATA_AUTOMATON);
8082
public static final IndexPrivilege MANAGE_FOLLOW_INDEX = new IndexPrivilege("manage_follow_index", MANAGE_FOLLOW_INDEX_AUTOMATON);
83+
public static final IndexPrivilege MANAGE_LEADER_INDEX = new IndexPrivilege("manage_leader_index", MANAGE_LEADER_INDEX_AUTOMATON);
8184
public static final IndexPrivilege MANAGE_ILM = new IndexPrivilege("manage_ilm", MANAGE_ILM_AUTOMATON);
8285

8386
private static final Map<String, IndexPrivilege> VALUES = MapBuilder.<String, IndexPrivilege>newMapBuilder()
@@ -95,6 +98,7 @@ public final class IndexPrivilege extends Privilege {
9598
.put("view_index_metadata", VIEW_METADATA)
9699
.put("read_cross_cluster", READ_CROSS_CLUSTER)
97100
.put("manage_follow_index", MANAGE_FOLLOW_INDEX)
101+
.put("manage_leader_index", MANAGE_LEADER_INDEX)
98102
.put("manage_ilm", MANAGE_ILM)
99103
.immutableMap();
100104

0 commit comments

Comments
 (0)