mirror of
https://github.com/elastic/elasticsearch.git
synced 2025-06-28 17:34:17 -04:00
disable validate when rewrite parameter is sent and the index access control list is non-null (#105709)
This commit is contained in:
parent
5a7b53a277
commit
5de1f176b4
4 changed files with 164 additions and 1 deletions
6
docs/changelog/105709.yaml
Normal file
6
docs/changelog/105709.yaml
Normal file
|
@ -0,0 +1,6 @@
|
|||
pr: 105709
|
||||
summary: Disable validate when rewrite parameter is sent and the index access control
|
||||
list is non-null
|
||||
area: Security
|
||||
type: bug
|
||||
issues: []
|
|
@ -303,6 +303,7 @@ import org.elasticsearch.xpack.security.authz.interceptor.SearchRequestCacheDisa
|
|||
import org.elasticsearch.xpack.security.authz.interceptor.SearchRequestInterceptor;
|
||||
import org.elasticsearch.xpack.security.authz.interceptor.ShardSearchRequestInterceptor;
|
||||
import org.elasticsearch.xpack.security.authz.interceptor.UpdateRequestInterceptor;
|
||||
import org.elasticsearch.xpack.security.authz.interceptor.ValidateRequestInterceptor;
|
||||
import org.elasticsearch.xpack.security.authz.restriction.WorkflowService;
|
||||
import org.elasticsearch.xpack.security.authz.store.CompositeRolesStore;
|
||||
import org.elasticsearch.xpack.security.authz.store.DeprecationRoleDescriptorConsumer;
|
||||
|
@ -999,7 +1000,8 @@ public class Security extends Plugin
|
|||
new UpdateRequestInterceptor(threadPool, getLicenseState()),
|
||||
new BulkShardRequestInterceptor(threadPool, getLicenseState()),
|
||||
new DlsFlsLicenseRequestInterceptor(threadPool.getThreadContext(), getLicenseState()),
|
||||
new SearchRequestCacheDisablingInterceptor(threadPool, getLicenseState())
|
||||
new SearchRequestCacheDisablingInterceptor(threadPool, getLicenseState()),
|
||||
new ValidateRequestInterceptor(threadPool, getLicenseState())
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.authz.interceptor;
|
||||
|
||||
import org.elasticsearch.ElasticsearchSecurityException;
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.IndicesRequest;
|
||||
import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryRequest;
|
||||
import org.elasticsearch.license.XPackLicenseState;
|
||||
import org.elasticsearch.rest.RestStatus;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.xpack.core.security.authz.accesscontrol.IndicesAccessControl;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class ValidateRequestInterceptor extends FieldAndDocumentLevelSecurityRequestInterceptor {
|
||||
|
||||
public ValidateRequestInterceptor(ThreadPool threadPool, XPackLicenseState licenseState) {
|
||||
super(threadPool.getThreadContext(), licenseState);
|
||||
}
|
||||
|
||||
@Override
|
||||
void disableFeatures(
|
||||
IndicesRequest indicesRequest,
|
||||
Map<String, IndicesAccessControl.IndexAccessControl> indexAccessControlByIndex,
|
||||
ActionListener<Void> listener
|
||||
) {
|
||||
final ValidateQueryRequest request = (ValidateQueryRequest) indicesRequest;
|
||||
if (indexAccessControlByIndex.values().stream().anyMatch(iac -> iac.getDocumentPermissions().hasDocumentLevelPermissions())) {
|
||||
if (hasRewrite(request)) {
|
||||
listener.onFailure(
|
||||
new ElasticsearchSecurityException(
|
||||
"Validate with rewrite isn't supported if document level security is enabled",
|
||||
RestStatus.BAD_REQUEST
|
||||
)
|
||||
);
|
||||
} else {
|
||||
listener.onResponse(null);
|
||||
}
|
||||
} else {
|
||||
listener.onResponse(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(IndicesRequest request) {
|
||||
if (request instanceof ValidateQueryRequest validateQueryRequest) {
|
||||
return hasRewrite(validateQueryRequest);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean hasRewrite(ValidateQueryRequest validateQueryRequest) {
|
||||
return validateQueryRequest.rewrite();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.xpack.security.authz.interceptor;
|
||||
|
||||
import org.elasticsearch.ElasticsearchSecurityException;
|
||||
import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryRequestBuilder;
|
||||
import org.elasticsearch.action.support.PlainActionFuture;
|
||||
import org.elasticsearch.client.internal.ElasticsearchClient;
|
||||
import org.elasticsearch.common.bytes.BytesArray;
|
||||
import org.elasticsearch.license.MockLicenseState;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.threadpool.TestThreadPool;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.xpack.core.security.authz.accesscontrol.IndicesAccessControl;
|
||||
import org.elasticsearch.xpack.core.security.authz.permission.DocumentPermissions;
|
||||
import org.elasticsearch.xpack.core.security.authz.permission.FieldPermissions;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.elasticsearch.xpack.core.security.SecurityField.DOCUMENT_LEVEL_SECURITY_FEATURE;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class ValidateRequestInterceptorTests extends ESTestCase {
|
||||
|
||||
private ThreadPool threadPool;
|
||||
private MockLicenseState licenseState;
|
||||
private ValidateRequestInterceptor interceptor;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
threadPool = new TestThreadPool("validate request interceptor tests");
|
||||
licenseState = mock(MockLicenseState.class);
|
||||
when(licenseState.isAllowed(DOCUMENT_LEVEL_SECURITY_FEATURE)).thenReturn(true);
|
||||
interceptor = new ValidateRequestInterceptor(threadPool, licenseState);
|
||||
}
|
||||
|
||||
@After
|
||||
public void stopThreadPool() {
|
||||
terminate(threadPool);
|
||||
}
|
||||
|
||||
public void testValidateRequestWithDLS() {
|
||||
final DocumentPermissions documentPermissions = DocumentPermissions.filteredBy(Set.of(new BytesArray("""
|
||||
{"term":{"username":"foo"}}"""))); // value does not matter
|
||||
ElasticsearchClient client = mock(ElasticsearchClient.class);
|
||||
ValidateQueryRequestBuilder builder = new ValidateQueryRequestBuilder(client);
|
||||
final String index = randomAlphaOfLengthBetween(3, 8);
|
||||
final PlainActionFuture<Void> listener1 = new PlainActionFuture<>();
|
||||
Map<String, IndicesAccessControl.IndexAccessControl> accessControlMap = Map.of(
|
||||
index,
|
||||
new IndicesAccessControl.IndexAccessControl(FieldPermissions.DEFAULT, documentPermissions)
|
||||
);
|
||||
// with DLS and rewrite enabled
|
||||
interceptor.disableFeatures(builder.setRewrite(true).request(), accessControlMap, listener1);
|
||||
ElasticsearchSecurityException exception = expectThrows(ElasticsearchSecurityException.class, () -> listener1.actionGet());
|
||||
assertThat(exception.getMessage(), containsString("Validate with rewrite isn't supported if document level security is enabled"));
|
||||
|
||||
// with DLS and rewrite disabled
|
||||
final PlainActionFuture<Void> listener2 = new PlainActionFuture<>();
|
||||
interceptor.disableFeatures(builder.setRewrite(false).request(), accessControlMap, listener2);
|
||||
assertNull(listener2.actionGet());
|
||||
|
||||
}
|
||||
|
||||
public void testValidateRequestWithOutDLS() {
|
||||
final DocumentPermissions documentPermissions = null; // no DLS
|
||||
ElasticsearchClient client = mock(ElasticsearchClient.class);
|
||||
ValidateQueryRequestBuilder builder = new ValidateQueryRequestBuilder(client);
|
||||
final String index = randomAlphaOfLengthBetween(3, 8);
|
||||
final PlainActionFuture<Void> listener1 = new PlainActionFuture<>();
|
||||
Map<String, IndicesAccessControl.IndexAccessControl> accessControlMap = Map.of(
|
||||
index,
|
||||
new IndicesAccessControl.IndexAccessControl(FieldPermissions.DEFAULT, documentPermissions)
|
||||
);
|
||||
// without DLS and rewrite enabled
|
||||
interceptor.disableFeatures(builder.setRewrite(true).request(), accessControlMap, listener1);
|
||||
assertNull(listener1.actionGet());
|
||||
|
||||
// without DLS and rewrite disabled
|
||||
final PlainActionFuture<Void> listener2 = new PlainActionFuture<>();
|
||||
interceptor.disableFeatures(builder.setRewrite(false).request(), accessControlMap, listener2);
|
||||
assertNull(listener2.actionGet());
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue