Skip to content

Commit

Permalink
[Extensions] Added headers to extensions request (#6826)
Browse files Browse the repository at this point in the history
* added headers to extensions rest request

Signed-off-by: Daulet <uralskdev@gmail.com>

* added tests for extension headers request

Signed-off-by: Daulet <uralskdev@gmail.com>

* applied spotless changes

Signed-off-by: Daulet <uralskdev@gmail.com>

* moved allowList/denyList code

Signed-off-by: Daulet <uralskdev@gmail.com>

* changed warning comment text

Signed-off-by: Daulet <uralskdev@gmail.com>

* Revert "changed warning comment text"

This reverts commit 3842f9e.

Signed-off-by: Daulet <uralskdev@gmail.com>

* changed warning comment text

Signed-off-by: Daulet <uralskdev@gmail.com>

* replaced List by Set in headers deny/allow list

Signed-off-by: Daulet <uralskdev@gmail.com>

* allowList, denyList moved to class level

Signed-off-by: Daulet <uralskdev@gmail.com>

* code of headers filtering moved to method

Signed-off-by: Daulet <uralskdev@gmail.com>

* Added tests for filterHeader(), changed path to uri in ExtensionRestRequest

Signed-off-by: Daulet <uralskdev@gmail.com>

* added uri and HttpVersion to ExtensionRestRequest

Signed-off-by: Daulet <uralskdev@gmail.com>

* fixed mistake in filteredHeaders

Signed-off-by: Daulet <uralskdev@gmail.com>

* fixed syntax mistakes

Signed-off-by: Daulet <uralskdev@gmail.com>

* fixed syntax mistakes 2

Signed-off-by: Daulet <uralskdev@gmail.com>

* Collectors import added to RestSendToExtensionAction

Signed-off-by: Daulet <uralskdev@gmail.com>

* added path to ExtensionRestRequest

Signed-off-by: Daulet <uralskdev@gmail.com>

* fixed compile errors 1

Signed-off-by: Daulet <uralskdev@gmail.com>

* fixed compile errors 2

Signed-off-by: Daulet <uralskdev@gmail.com>

* corrected tests for new ExtensionRestRequest

Signed-off-by: Daulet <uralskdev@gmail.com>

---------

Signed-off-by: Daulet <uralskdev@gmail.com>
  • Loading branch information
nassipkali authored Apr 7, 2023
1 parent c765e3a commit 0db20d9
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.opensearch.rest.RestRequest;
import org.opensearch.rest.RestRequest.Method;
import org.opensearch.transport.TransportRequest;
import org.opensearch.http.HttpRequest;

import java.io.IOException;
import java.util.ArrayList;
Expand All @@ -37,13 +38,16 @@
public class ExtensionRestRequest extends TransportRequest {

private Method method;
private String uri;
private String path;
private Map<String, String> params;
private Map<String, List<String>> headers;
private XContentType xContentType = null;
private BytesReference content;
// The owner of this request object
// Will be replaced with PrincipalIdentifierToken class from feature/identity
private String principalIdentifierToken;
private HttpRequest.HttpVersion httpVersion;

// Tracks consumed parameters and content
private final Set<String> consumedParams = new HashSet<>();
Expand All @@ -53,26 +57,35 @@ public class ExtensionRestRequest extends TransportRequest {
* This object can be instantiated given method, uri, params, content and identifier
*
* @param method of type {@link Method}
* @param path the REST path string (excluding the query)
* @param uri the REST uri string (excluding the query)
* @param path the REST path
* @param params the REST params
* @param headers the REST headers
* @param xContentType the content type, or null for plain text or no content
* @param content the REST request content
* @param principalIdentifier the owner of this request
* @param httpVersion the REST HTTP protocol version
*/
public ExtensionRestRequest(
Method method,
String uri,
String path,
Map<String, String> params,
Map<String, List<String>> headers,
XContentType xContentType,
BytesReference content,
String principalIdentifier
String principalIdentifier,
HttpRequest.HttpVersion httpVersion
) {
this.method = method;
this.uri = uri;
this.path = path;
this.params = params;
this.headers = headers;
this.xContentType = xContentType;
this.content = content;
this.principalIdentifierToken = principalIdentifier;
this.httpVersion = httpVersion;
}

/**
Expand All @@ -84,27 +97,33 @@ public ExtensionRestRequest(
public ExtensionRestRequest(StreamInput in) throws IOException {
super(in);
method = in.readEnum(RestRequest.Method.class);
uri = in.readString();
path = in.readString();
params = in.readMap(StreamInput::readString, StreamInput::readString);
headers = in.readMap(StreamInput::readString, StreamInput::readStringList);
if (in.readBoolean()) {
xContentType = in.readEnum(XContentType.class);
}
content = in.readBytesReference();
principalIdentifierToken = in.readString();
httpVersion = in.readEnum(HttpRequest.HttpVersion.class);
}

@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeEnum(method);
out.writeString(uri);
out.writeString(path);
out.writeMap(params, StreamOutput::writeString, StreamOutput::writeString);
out.writeMap(headers, StreamOutput::writeString, StreamOutput::writeStringCollection);
out.writeBoolean(xContentType != null);
if (xContentType != null) {
out.writeEnum(xContentType);
}
out.writeBytesReference(content);
out.writeString(principalIdentifierToken);
out.writeEnum(httpVersion);
}

/**
Expand All @@ -116,6 +135,15 @@ public Method method() {
return method;
}

/**
* Gets the REST uri
*
* @return This REST request's uri
*/
public String uri() {
return uri;
}

/**
* Gets the REST path
*
Expand Down Expand Up @@ -196,6 +224,14 @@ public List<String> consumedParams() {
return new ArrayList<>(consumedParams);
}

/**
* Gets the headers of request
* @return a map of request headers
*/
public Map<String, List<String>> headers() {
return headers;
}

/**
* Gets the content type, if any.
*
Expand Down Expand Up @@ -255,20 +291,33 @@ public String getRequestIssuerIdentity() {
return principalIdentifierToken;
}

/**
* @return This REST request's HTTP protocol version
*/
public HttpRequest.HttpVersion protocolVersion() {
return httpVersion;
}

@Override
public String toString() {
return "ExtensionRestRequest{method="
+ method
+ ", uri="
+ uri
+ ", path="
+ path
+ ", params="
+ params
+ ", headers="
+ headers.toString()
+ ", xContentType="
+ xContentType
+ ", contentLength="
+ content.length()
+ ", requester="
+ principalIdentifierToken
+ ", httpVersion="
+ httpVersion
+ "}";
}

Expand All @@ -278,15 +327,18 @@ public boolean equals(Object obj) {
if (obj == null || getClass() != obj.getClass()) return false;
ExtensionRestRequest that = (ExtensionRestRequest) obj;
return Objects.equals(method, that.method)
&& Objects.equals(uri, that.uri)
&& Objects.equals(path, that.path)
&& Objects.equals(params, that.params)
&& Objects.equals(headers, that.headers)
&& Objects.equals(xContentType, that.xContentType)
&& Objects.equals(content, that.content)
&& Objects.equals(principalIdentifierToken, that.principalIdentifierToken);
&& Objects.equals(principalIdentifierToken, that.principalIdentifierToken)
&& Objects.equals(httpVersion, that.httpVersion);
}

@Override
public int hashCode() {
return Objects.hash(method, path, params, xContentType, content, principalIdentifierToken);
return Objects.hash(method, uri, path, params, headers, xContentType, content, principalIdentifierToken, httpVersion);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,16 @@
import org.opensearch.transport.TransportException;
import org.opensearch.transport.TransportResponseHandler;
import org.opensearch.transport.TransportService;
import org.opensearch.http.HttpRequest;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.Principal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -61,6 +64,9 @@ public String getName() {
private final DiscoveryExtensionNode discoveryExtensionNode;
private final TransportService transportService;

private static final Set<String> allowList = Set.of("Content-Type");
private static final Set<String> denyList = Set.of("Authorization", "Proxy-Authorization");

/**
* Instantiates this object using a {@link RegisterRestActionsRequest} to populate the routes.
*
Expand Down Expand Up @@ -103,13 +109,26 @@ public List<Route> routes() {
return this.routes;
}

public Map<String, List<String>> filterHeaders(Map<String, List<String>> headers, Set<String> allowList, Set<String> denyList) {
Map<String, List<String>> filteredHeaders = headers.entrySet()
.stream()
.filter(e -> !denyList.contains(e.getKey()))
.filter(e -> allowList.contains(e.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
return filteredHeaders;
}

@Override
public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {
Method method = request.method();
HttpRequest httpRequest = request.getHttpRequest();
String path = request.path();
Method method = request.method();
String uri = httpRequest.uri();
Map<String, String> params = request.params();
Map<String, List<String>> headers = request.getHeaders();
XContentType contentType = request.getXContentType();
BytesReference content = request.content();
HttpRequest.HttpVersion httpVersion = httpRequest.protocolVersion();

if (path.startsWith(pathPrefix)) {
path = path.substring(pathPrefix.length());
Expand Down Expand Up @@ -160,17 +179,30 @@ public String executor() {
return ThreadPool.Names.GENERIC;
}
};

try {
// Will be replaced with ExtensionTokenProcessor and PrincipalIdentifierToken classes from feature/identity
final String extensionTokenProcessor = "placeholder_token_processor";
final String requestIssuerIdentity = "placeholder_request_issuer_identity";

Map<String, List<String>> filteredHeaders = filterHeaders(headers, allowList, denyList);

transportService.sendRequest(
discoveryExtensionNode,
ExtensionsManager.REQUEST_REST_EXECUTE_ON_EXTENSION_ACTION,
// HERE BE DRAGONS - DO NOT INCLUDE HEADERS
// DO NOT INCLUDE HEADERS WITH SECURITY OR PRIVACY INFORMATION
// SEE https://github.com/opensearch-project/OpenSearch/issues/4429
new ExtensionRestRequest(method, path, params, contentType, content, requestIssuerIdentity),
new ExtensionRestRequest(
method,
uri,
path,
params,
filteredHeaders,
contentType,
content,
requestIssuerIdentity,
httpVersion
),
restExecuteOnExtensionResponseHandler
);
inProgressFuture.orTimeout(ExtensionsManager.EXTENSION_REQUEST_WAIT_TIMEOUT, TimeUnit.SECONDS).join();
Expand Down
Loading

0 comments on commit 0db20d9

Please sign in to comment.