Skip to content

Commit

Permalink
Router: Authorize permissionless internal requests. (apache#16419)
Browse files Browse the repository at this point in the history
* Router: Authorize permissionless internal requests.

Router-internal requests like /proxy/enabled and errors for invalid
requests should not require permissions, but they still need to be
authorized in order to satisfy the PreResponseAuthorizationCheckFilter.
This patch adds authorization checks that do not require any particular
permissions.

* Fix tests.
  • Loading branch information
gianm authored Jun 5, 2024
1 parent 1040a29 commit 717e634
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
import org.apache.druid.java.util.common.StringUtils;
import org.apache.druid.server.initialization.jetty.StandardResponseHeaderFilterHolder;
import org.apache.druid.server.security.AuthConfig;
import org.apache.druid.server.security.AuthorizationUtils;
import org.apache.druid.server.security.AuthorizerMapper;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Response;
Expand All @@ -41,6 +43,7 @@
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
import java.util.concurrent.TimeUnit;

public class AsyncManagementForwardingServlet extends AsyncProxyServlet
Expand Down Expand Up @@ -71,21 +74,24 @@ public class AsyncManagementForwardingServlet extends AsyncProxyServlet
private final DruidHttpClientConfig httpClientConfig;
private final DruidLeaderSelector coordLeaderSelector;
private final DruidLeaderSelector overlordLeaderSelector;
private final AuthorizerMapper authorizerMapper;

@Inject
public AsyncManagementForwardingServlet(
@Json ObjectMapper jsonMapper,
@Global Provider<HttpClient> httpClientProvider,
@Global DruidHttpClientConfig httpClientConfig,
@Coordinator DruidLeaderSelector coordLeaderSelector,
@IndexingService DruidLeaderSelector overlordLeaderSelector
@IndexingService DruidLeaderSelector overlordLeaderSelector,
AuthorizerMapper authorizerMapper
)
{
this.jsonMapper = jsonMapper;
this.httpClientProvider = httpClientProvider;
this.httpClientConfig = httpClientConfig;
this.coordLeaderSelector = coordLeaderSelector;
this.overlordLeaderSelector = overlordLeaderSelector;
this.authorizerMapper = authorizerMapper;
}

@Override
Expand All @@ -110,9 +116,11 @@ protected void service(HttpServletRequest request, HttpServletResponse response)
request.getRequestURI().substring(ARBITRARY_OVERLORD_BASE_PATH.length())
);
} else if (ENABLED_PATH.equals(requestURI)) {
authorizeNoPermissionsNeeded(request);
handleEnabledRequest(response);
return;
} else {
authorizeNoPermissionsNeeded(request);
handleInvalidRequest(
response,
StringUtils.format("Unsupported proxy destination[%s]", request.getRequestURI()),
Expand All @@ -122,6 +130,7 @@ protected void service(HttpServletRequest request, HttpServletResponse response)
}

if (currentLeader == null) {
authorizeNoPermissionsNeeded(request);
handleInvalidRequest(
response,
StringUtils.format(
Expand Down Expand Up @@ -191,6 +200,14 @@ protected void onServerResponseHeaders(
super.onServerResponseHeaders(clientRequest, proxyResponse, serverResponse);
}

/**
* Authorizes router-internal requests that do not require any permissions. (But do require an authenticated user.)
*/
private void authorizeNoPermissionsNeeded(HttpServletRequest request)
{
AuthorizationUtils.authorizeAllResourceActions(request, Collections.emptyList(), authorizerMapper);
}

private void handleInvalidRequest(HttpServletResponse response, String errorMessage, int statusCode) throws IOException
{
if (!response.isCommitted()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@
import org.apache.druid.server.initialization.ServerConfig;
import org.apache.druid.server.initialization.jetty.JettyServerInitUtils;
import org.apache.druid.server.initialization.jetty.JettyServerInitializer;
import org.apache.druid.server.security.AllowAllAuthenticator;
import org.apache.druid.server.security.AllowAllAuthorizer;
import org.apache.druid.server.security.AuthenticationUtils;
import org.apache.druid.server.security.AuthorizerMapper;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
Expand Down Expand Up @@ -321,7 +325,7 @@ public void testOverlordProxyLeader() throws Exception
}

@Test
public void testProxyEnebledCheck() throws Exception
public void testProxyEnabledCheck() throws Exception
{
HttpURLConnection connection = ((HttpURLConnection)
new URL(StringUtils.format("http://localhost:%d/proxy/enabled", port)).openConnection());
Expand Down Expand Up @@ -491,7 +495,8 @@ public String getCurrentLeader()
injector.getProvider(HttpClient.class),
injector.getInstance(DruidHttpClientConfig.class),
coordinatorLeaderSelector,
overlordLeaderSelector
overlordLeaderSelector,
new AuthorizerMapper(ImmutableMap.of("allowAll", new AllowAllAuthorizer()))
)
);

Expand All @@ -502,6 +507,7 @@ public String getCurrentLeader()
root.addServlet(holder, "/druid/indexer/*");
root.addServlet(holder, "/proxy/*");

AuthenticationUtils.addAuthenticationFilterChain(root, ImmutableList.of(new AllowAllAuthenticator()));
JettyServerInitUtils.addExtensionFilters(root, injector);

final HandlerList handlerList = new HandlerList();
Expand Down

0 comments on commit 717e634

Please sign in to comment.