[NO ISSUE][API] Add ability to identify secure servlet requests
Change-Id: Ia693e29a47b513a63fdce80383da90ba165c28d6
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/3603
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Till Westmann <tillw@apache.org>
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ClusterApiServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ClusterApiServlet.java
index ce30637..bdc1bd7 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ClusterApiServlet.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/ClusterApiServlet.java
@@ -145,7 +145,8 @@
}
protected String resolveClusterUrl(IServletRequest request, String pathToNode) {
- final StringBuilder requestURL = new StringBuilder("http://");
+ final StringBuilder requestURL = new StringBuilder(request.getScheme().name());
+ requestURL.append("://");
requestURL.append(request.getHeader(HttpHeaderNames.HOST));
requestURL.append(request.getHttpRequest().uri());
if (requestURL.charAt(requestURL.length() - 1) != '/') {
diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/api/IServletRequest.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/api/IServletRequest.java
index 7dae0b5..8af9f23 100644
--- a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/api/IServletRequest.java
+++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/api/IServletRequest.java
@@ -23,6 +23,7 @@
import java.util.Set;
import io.netty.handler.codec.http.FullHttpRequest;
+import io.netty.handler.codec.http.HttpScheme;
/**
* An Http Request instance
@@ -81,4 +82,9 @@
* @return the remote address
*/
InetSocketAddress getRemoteAddress();
+
+ /**
+ * Indicates which scheme the client used making this request
+ */
+ HttpScheme getScheme();
}
diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/BaseRequest.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/BaseRequest.java
index d681d81..69f7c5f 100644
--- a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/BaseRequest.java
+++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/BaseRequest.java
@@ -18,7 +18,6 @@
*/
package org.apache.hyracks.http.server;
-import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.Collections;
import java.util.HashMap;
@@ -31,25 +30,28 @@
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.FullHttpRequest;
+import io.netty.handler.codec.http.HttpScheme;
import io.netty.handler.codec.http.QueryStringDecoder;
public class BaseRequest implements IServletRequest {
protected final FullHttpRequest request;
protected final Map<String, List<String>> parameters;
protected final InetSocketAddress remoteAddress;
+ protected final HttpScheme scheme;
- public static IServletRequest create(ChannelHandlerContext ctx, FullHttpRequest request) throws IOException {
+ public static IServletRequest create(ChannelHandlerContext ctx, FullHttpRequest request, HttpScheme scheme) {
QueryStringDecoder decoder = new QueryStringDecoder(request.uri());
Map<String, List<String>> param = decoder.parameters();
InetSocketAddress remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress();
- return new BaseRequest(request, remoteAddress, param);
+ return new BaseRequest(request, remoteAddress, param, scheme);
}
protected BaseRequest(FullHttpRequest request, InetSocketAddress remoteAddress,
- Map<String, List<String>> parameters) {
+ Map<String, List<String>> parameters, HttpScheme scheme) {
this.request = request;
this.remoteAddress = remoteAddress;
this.parameters = parameters;
+ this.scheme = scheme;
}
@Override
@@ -86,4 +88,9 @@
public InetSocketAddress getRemoteAddress() {
return remoteAddress;
}
+
+ @Override
+ public HttpScheme getScheme() {
+ return scheme;
+ }
}
diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/FormUrlEncodedRequest.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/FormUrlEncodedRequest.java
index 81cd04e..0e57d8d 100644
--- a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/FormUrlEncodedRequest.java
+++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/FormUrlEncodedRequest.java
@@ -31,11 +31,12 @@
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.FullHttpRequest;
+import io.netty.handler.codec.http.HttpScheme;
import io.netty.handler.codec.http.QueryStringDecoder;
public class FormUrlEncodedRequest extends BaseRequest implements IServletRequest {
- public static IServletRequest create(ChannelHandlerContext ctx, FullHttpRequest request) {
+ public static IServletRequest create(ChannelHandlerContext ctx, FullHttpRequest request, HttpScheme scheme) {
Charset charset = HttpUtil.getRequestCharset(request);
Map<String, List<String>> parameters = new LinkedHashMap<>();
URLEncodedUtils.parse(request.content().toString(charset), charset).forEach(
@@ -43,11 +44,11 @@
new QueryStringDecoder(request.uri()).parameters()
.forEach((name, value) -> parameters.computeIfAbsent(name, a -> new ArrayList<>()).addAll(value));
InetSocketAddress remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress();
- return new FormUrlEncodedRequest(request, remoteAddress, parameters);
+ return new FormUrlEncodedRequest(request, remoteAddress, parameters, scheme);
}
private FormUrlEncodedRequest(FullHttpRequest request, InetSocketAddress remoteAddress,
- Map<String, List<String>> parameters) {
- super(request, remoteAddress, parameters);
+ Map<String, List<String>> parameters, HttpScheme scheme) {
+ super(request, remoteAddress, parameters, scheme);
}
}
diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServer.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServer.java
index d9902da..2a7b47e 100644
--- a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServer.java
+++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServer.java
@@ -48,6 +48,7 @@
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.FullHttpRequest;
+import io.netty.handler.codec.http.HttpScheme;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
@@ -404,6 +405,10 @@
return closedHandler;
}
+ public HttpScheme getScheme() {
+ return HttpScheme.HTTP;
+ }
+
@Override
public String toString() {
return "{\"class\":\"" + getClass().getSimpleName() + "\",\"address\":" + address + ",\"state\":\"" + getState()
diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServerHandler.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServerHandler.java
index fe6a431..4882572 100644
--- a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServerHandler.java
+++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/HttpServerHandler.java
@@ -18,6 +18,8 @@
*/
package org.apache.hyracks.http.server;
+import static org.apache.hyracks.http.server.utils.HttpUtil.X_FORWARDED_PROTO;
+
import java.io.IOException;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;
@@ -42,6 +44,7 @@
import io.netty.handler.codec.http.HttpHeaderValues;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
+import io.netty.handler.codec.http.HttpScheme;
public class HttpServerHandler<T extends HttpServer> extends SimpleChannelInboundHandler<Object>
implements ChannelFutureListener {
@@ -130,7 +133,10 @@
private void submit(ChannelHandlerContext ctx, IServlet servlet, FullHttpRequest request) throws IOException {
IServletRequest servletRequest;
try {
- servletRequest = HttpUtil.toServletRequest(ctx, request);
+ HttpScheme scheme =
+ server.getScheme() == HttpScheme.HTTPS || "https".equals(request.headers().get(X_FORWARDED_PROTO))
+ ? HttpScheme.HTTPS : HttpScheme.HTTP;
+ servletRequest = HttpUtil.toServletRequest(ctx, request, scheme);
} catch (IllegalArgumentException e) {
LOGGER.log(Level.WARN, "Failure Decoding Request", e);
respond(ctx, request, HttpResponseStatus.BAD_REQUEST);
diff --git a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/utils/HttpUtil.java b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/utils/HttpUtil.java
index 34ca2c4..0f857bd 100644
--- a/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/utils/HttpUtil.java
+++ b/hyracks-fullstack/hyracks/hyracks-http/src/main/java/org/apache/hyracks/http/server/utils/HttpUtil.java
@@ -44,6 +44,7 @@
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaderValues;
import io.netty.handler.codec.http.HttpRequest;
+import io.netty.handler.codec.http.HttpScheme;
import io.netty.util.AsciiString;
public class HttpUtil {
@@ -51,6 +52,8 @@
private static final Pattern PARENT_DIR = Pattern.compile("/[^./]+/\\.\\./");
private static final Charset DEFAULT_RESPONSE_CHARSET = StandardCharsets.UTF_8;
+ public static final AsciiString X_FORWARDED_PROTO = AsciiString.cached("x-forwarded-proto");
+
private HttpUtil() {
}
@@ -80,10 +83,10 @@
return parameter == null ? null : String.join(",", parameter);
}
- public static IServletRequest toServletRequest(ChannelHandlerContext ctx, FullHttpRequest request)
- throws IOException {
+ public static IServletRequest toServletRequest(ChannelHandlerContext ctx, FullHttpRequest request,
+ HttpScheme scheme) {
return ContentType.APPLICATION_X_WWW_FORM_URLENCODED.equals(getContentTypeOnly(request))
- ? FormUrlEncodedRequest.create(ctx, request) : BaseRequest.create(ctx, request);
+ ? FormUrlEncodedRequest.create(ctx, request, scheme) : BaseRequest.create(ctx, request, scheme);
}
public static String getContentTypeOnly(IServletRequest request) {