Skip to content
This repository has been archived by the owner on Jan 6, 2022. It is now read-only.

Rest API Backport #25

Open
wants to merge 1 commit into
base: 6.5.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,5 @@ data/
puppet/.vagrant
test.sh
.vagrant/
.idea/
*.iml
6 changes: 3 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
</parent>

<artifactId>opendistro_security_advanced_modules</artifactId>
<version>0.7.0.1</version>
<version>0.7.0.2</version>
<packaging>jar</packaging>

<name>Open Distro Security Advanced Modules for Elasticsearch</name>
Expand All @@ -34,7 +34,7 @@
<inceptionYear>2016</inceptionYear>

<properties>
<security.version>0.7.0.1</security.version>
<security.version>0.7.0.2</security.version>
<elasticsearch.version>6.5.4</elasticsearch.version>

<!-- deps -->
Expand All @@ -55,7 +55,7 @@
<url>https://github.com/opendistro-for-elasticsearch/security-advanced-modules</url>
<connection>scm:git:[email protected]:opendistro-for-elasticsearch/security-advanced-modules.git</connection>
<developerConnection>scm:git:[email protected]:opendistro-for-elasticsearch/security-advanced-modules.git</developerConnection>
<tag>v0.7.0.1</tag>
<tag>v0.7.0.2</tag>
</scm>

<issueManagement>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

package com.amazon.opendistroforelasticsearch.security.dlic.rest.api;

import java.io.IOException;
import java.nio.file.Path;

import org.elasticsearch.client.Client;
Expand All @@ -23,60 +24,91 @@
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.rest.BytesRestResponse;
import org.elasticsearch.rest.RestChannel;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.RestRequest.Method;
import org.elasticsearch.rest.RestResponse;
import org.elasticsearch.rest.RestRequest.Method;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.threadpool.ThreadPool;

import com.amazon.opendistroforelasticsearch.security.auditlog.AuditLog;
import com.amazon.opendistroforelasticsearch.security.configuration.AdminDNs;
import com.amazon.opendistroforelasticsearch.security.configuration.IndexBaseConfigurationRepository;
import com.amazon.opendistroforelasticsearch.security.dlic.rest.support.Utils;
import com.amazon.opendistroforelasticsearch.security.dlic.rest.validation.AbstractConfigurationValidator;
import com.amazon.opendistroforelasticsearch.security.dlic.rest.validation.NoOpValidator;
import com.amazon.opendistroforelasticsearch.security.dlic.rest.validation.SecurityConfigValidator;
import com.amazon.opendistroforelasticsearch.security.privileges.PrivilegesEvaluator;
import com.amazon.opendistroforelasticsearch.security.ssl.transport.PrincipalExtractor;
import com.amazon.opendistroforelasticsearch.security.support.ConfigConstants;

public class OpenDistroSecurityConfigAction extends AbstractApiAction {
public class OpenDistroSecurityConfigAction extends PatchableResourceApiAction {

private final boolean allowPutOrPatch;

@Inject
public OpenDistroSecurityConfigAction(final Settings settings, final Path configPath, final RestController controller, final Client client,
final AdminDNs adminDNs, final IndexBaseConfigurationRepository cl, final ClusterService cs,
final PrincipalExtractor principalExtractor, final PrivilegesEvaluator evaluator, ThreadPool threadPool, AuditLog auditLog) {
final AdminDNs adminDNs, final IndexBaseConfigurationRepository cl, final ClusterService cs, final PrincipalExtractor principalExtractor,
final PrivilegesEvaluator evaluator, ThreadPool threadPool, AuditLog auditLog) {
super(settings, configPath, controller, client, adminDNs, cl, cs, principalExtractor, evaluator, threadPool, auditLog);
controller.registerHandler(Method.GET, "/_opendistro/_security/api/config/", this);
}

allowPutOrPatch = settings.getAsBoolean(ConfigConstants.OPENDISTRO_SECURITY_UNSUPPORTED_RESTAPI_ALLOW_SECURITYCONFIG_MODIFICATION, false);

controller.registerHandler(Method.GET, "/_opendistro/_security/api/securityconfig/", this);

if (allowPutOrPatch) {
controller.registerHandler(Method.PUT, "/_opendistro/_security/api/securityconfig/{name}", this);
controller.registerHandler(Method.PATCH, "/_opendistro/_security/api/securityconfig/", this);
}

}

@Override
protected Tuple<String[], RestResponse> handleGet(RestRequest request, Client client,
final Settings.Builder additionalSettingsBuilder) throws Throwable {
protected Tuple<String[], RestResponse> handleApiRequest(RestRequest request, Client client) throws Throwable {
if (request.method() == Method.PATCH && !allowPutOrPatch) {
return notImplemented(Method.PATCH);
} else {
return super.handleApiRequest(request, client);
}
}

@Override
protected Tuple<String[], RestResponse> handleGet(RestRequest request, Client client, final Settings.Builder additionalSettingsBuilder) throws IOException {
final Settings configurationSettings = loadAsSettings(getConfigName(), true);

return new Tuple<String[], RestResponse>(new String[0],
new BytesRestResponse(RestStatus.OK, convertToJson(configurationSettings)));
}

@Override
protected Tuple<String[], RestResponse> handlePut(final RestRequest request, final Client client,
final Settings.Builder additionalSettings) throws Throwable {
return notImplemented(Method.PUT);
protected Tuple<String[], RestResponse> handlePut(final RestRequest request, final Client client, final Settings.Builder additionalSettings)
throws Throwable {
if (allowPutOrPatch) {
if (!"opendistro_security".equals(request.param("name"))) {
return badRequestResponse("name must be opendistro_security");
}
return super.handlePut(request, client, additionalSettings);
} else {
return notImplemented(Method.PUT);
}
}

@Override
protected Tuple<String[], RestResponse> handleDelete(final RestRequest request, final Client client,
final Settings.Builder additionalSettings) throws Throwable {
protected Tuple<String[], RestResponse> handleDelete(final RestRequest request, final Client client, final Settings.Builder additionalSettings) {
return notImplemented(Method.DELETE);
}

@Override
protected Tuple<String[], RestResponse> handlePost(final RestRequest request, final Client client, final Settings.Builder additionalSetting)
throws IOException {
return notImplemented(Method.POST);
}

@Override
protected AbstractConfigurationValidator getValidator(RestRequest request, BytesReference ref, Object... param) {
return new NoOpValidator(request, ref, this.settings, param);
return new SecurityConfigValidator(request, ref, this.settings, param);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright 2015-2018 _floragunn_ GmbH
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/*
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/


package com.amazon.opendistroforelasticsearch.security.dlic.rest.validation;

import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.rest.RestRequest;

public class SecurityConfigValidator extends AbstractConfigurationValidator {

public SecurityConfigValidator(final RestRequest request, BytesReference ref, final Settings esSettings, Object... param) {
super(request, ref, esSettings, param);
this.payloadMandatory = true;
allowedKeys.put("dynamic", DataType.OBJECT);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* Copyright 2015-2018 _floragunn_ GmbH
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/*
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/


package com.amazon.opendistroforelasticsearch.security.dlic.rest.api;

import org.apache.http.Header;
import org.apache.http.HttpStatus;
import org.elasticsearch.common.settings.Settings;
import org.junit.Assert;
import org.junit.Test;

import com.amazon.opendistroforelasticsearch.security.support.ConfigConstants;
import com.amazon.opendistroforelasticsearch.security.test.helper.file.FileHelper;
import com.amazon.opendistroforelasticsearch.security.test.helper.rest.RestHelper.HttpResponse;

public class SecurityConfigApiTest extends AbstractRestApiUnitTest {

@Test
public void testSecurityConfigApiRead() throws Exception {

setup();

rh.keystore = "restapi/kirk-keystore.jks";
rh.sendHTTPClientCertificate = true;

HttpResponse response = rh.executeGetRequest("/_opendistro/_security/api/securityconfig", new Header[0]);
Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode());

response = rh.executePutRequest("/_opendistro/_security/api/securityconfig", "{\"xxx\": 1}", new Header[0]);
Assert.assertEquals(HttpStatus.SC_METHOD_NOT_ALLOWED, response.getStatusCode());

response = rh.executePostRequest("/_opendistro/_security/api/securityconfig", "{\"xxx\": 1}", new Header[0]);
Assert.assertEquals(HttpStatus.SC_METHOD_NOT_ALLOWED, response.getStatusCode());

response = rh.executePatchRequest("/_opendistro/_security/api/securityconfig", "{\"xxx\": 1}", new Header[0]);
Assert.assertEquals(HttpStatus.SC_METHOD_NOT_ALLOWED, response.getStatusCode());

response = rh.executeDeleteRequest("/_opendistro/_security/api/securityconfig", new Header[0]);
Assert.assertEquals(HttpStatus.SC_METHOD_NOT_ALLOWED, response.getStatusCode());

}

@Test
public void testSecurityConfigApiWrite() throws Exception {

Settings settings = Settings.builder().put(ConfigConstants.OPENDISTRO_SECURITY_UNSUPPORTED_RESTAPI_ALLOW_SECURITYCONFIG_MODIFICATION, true).build();
setup(settings);

rh.keystore = "restapi/kirk-keystore.jks";
rh.sendHTTPClientCertificate = true;

HttpResponse response = rh.executeGetRequest("/_opendistro/_security/api/securityconfig", new Header[0]);
Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode());

response = rh.executePutRequest("/_opendistro/_security/api/securityconfig/opendistro_security_xxx", FileHelper.loadFile("restapi/securityconfig.json"), new Header[0]);
Assert.assertEquals(HttpStatus.SC_BAD_REQUEST, response.getStatusCode());

response = rh.executePutRequest("/_opendistro/_security/api/securityconfig/opendistro_security", FileHelper.loadFile("restapi/securityconfig.json"), new Header[0]);
Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode());

response = rh.executeGetRequest("/_opendistro/_security/api/securityconfig", new Header[0]);
System.out.println(response.getBody());
Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode());

response = rh.executePostRequest("/_opendistro/_security/api/securityconfig", "{\"xxx\": 1}", new Header[0]);
Assert.assertEquals(HttpStatus.SC_METHOD_NOT_ALLOWED, response.getStatusCode());

response = rh.executePatchRequest("/_opendistro/_security/api/securityconfig", "[{\"op\": \"replace\",\"path\": \"/opendistro_security/dynamic/hosts_resolver_mode\",\"value\": \"other\"}]", new Header[0]);
Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode());

response = rh.executeDeleteRequest("/_opendistro/_security/api/securityconfig", new Header[0]);
Assert.assertEquals(HttpStatus.SC_METHOD_NOT_ALLOWED, response.getStatusCode());

}
}
Loading