Skip to content

Commit

Permalink
Return forbidden when authorization fails for sql query canceling (ap…
Browse files Browse the repository at this point in the history
…ache#11710)

Switching http response code for authorization failures for sql query canceling to match to sql query posting.
  • Loading branch information
jihoonson authored Sep 15, 2021
1 parent 7220d04 commit 0cbd71e
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 10 deletions.
3 changes: 1 addition & 2 deletions sql/src/main/java/org/apache/druid/sql/http/SqlResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -268,8 +268,7 @@ public Response cancelQuery(
lifecycles.forEach(SqlLifecycle::cancel);
return Response.status(Status.ACCEPTED).build();
} else {
// Return 404 for authorization failures as well
return Response.status(Status.NOT_FOUND).build();
return Response.status(Status.FORBIDDEN).build();
}
}
}
52 changes: 44 additions & 8 deletions sql/src/test/java/org/apache/druid/sql/http/SqlResourceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
import org.apache.druid.server.scheduling.HiLoQueryLaningStrategy;
import org.apache.druid.server.scheduling.ManualQueryPrioritizationStrategy;
import org.apache.druid.server.security.AuthConfig;
import org.apache.druid.server.security.AuthenticationResult;
import org.apache.druid.server.security.ForbiddenException;
import org.apache.druid.sql.SqlLifecycle;
import org.apache.druid.sql.SqlLifecycleFactory;
Expand Down Expand Up @@ -986,7 +987,7 @@ public void testTooManyRequests() throws Exception
ImmutableMap.of("priority", -5, "sqlQueryId", sqlQueryId),
null
),
makeExpectedReq()
makeRegularUserReq()
);
}
catch (Exception e) {
Expand Down Expand Up @@ -1053,7 +1054,7 @@ public void testCancelBetweenValidateAndPlan() throws Exception
Future<Response> future = executorService.submit(
() -> resource.doPost(
createSimpleQueryWithId(sqlQueryId, "SELECT DISTINCT dim1 FROM foo"),
makeExpectedReq()
makeRegularUserReq()
)
);
Assert.assertTrue(validateAndAuthorizeLatch.await(1, TimeUnit.SECONDS));
Expand Down Expand Up @@ -1084,7 +1085,7 @@ public void testCancelBetweenPlanAndExecute() throws Exception
Future<Response> future = executorService.submit(
() -> resource.doPost(
createSimpleQueryWithId(sqlQueryId, "SELECT DISTINCT dim1 FROM foo"),
makeExpectedReq()
makeRegularUserReq()
)
);
Assert.assertTrue(planLatch.await(1, TimeUnit.SECONDS));
Expand Down Expand Up @@ -1114,7 +1115,7 @@ public void testCancelInvalidQuery() throws Exception
Future<Response> future = executorService.submit(
() -> resource.doPost(
createSimpleQueryWithId(sqlQueryId, "SELECT DISTINCT dim1 FROM foo"),
makeExpectedReq()
makeRegularUserReq()
)
);
Assert.assertTrue(planLatch.await(1, TimeUnit.SECONDS));
Expand All @@ -1128,6 +1129,31 @@ public void testCancelInvalidQuery() throws Exception
Assert.assertEquals(Status.OK.getStatusCode(), response.getStatus());
}

@Test
public void testCancelForbidden() throws Exception
{
final String sqlQueryId = "toCancel";
CountDownLatch planLatch = new CountDownLatch(1);
planLatchSupplier.set(new NonnullPair<>(planLatch, true));
CountDownLatch execLatch = new CountDownLatch(1);
executeLatchSupplier.set(new NonnullPair<>(execLatch, false));
Future<Response> future = executorService.submit(
() -> resource.doPost(
createSimpleQueryWithId(sqlQueryId, "SELECT DISTINCT dim1 FROM forbiddenDatasource"),
makeSuperUserReq()
)
);
Assert.assertTrue(planLatch.await(1, TimeUnit.SECONDS));
Response response = resource.cancelQuery(sqlQueryId, mockRequestForCancel());
Assert.assertEquals(Status.FORBIDDEN.getStatusCode(), response.getStatus());

Assert.assertFalse(lifecycleManager.getAll(sqlQueryId).isEmpty());

execLatch.countDown();
response = future.get();
Assert.assertEquals(Status.OK.getStatusCode(), response.getStatus());
}

@SuppressWarnings("unchecked")
private void checkSqlRequestLog(boolean success)
{
Expand Down Expand Up @@ -1222,24 +1248,34 @@ private Pair<QueryException, String> doPostRaw(final SqlQuery query, final HttpS
}
}

private HttpServletRequest makeExpectedReq()
private HttpServletRequest makeSuperUserReq()
{
return makeExpectedReq(CalciteTests.SUPER_USER_AUTH_RESULT);
}

private HttpServletRequest makeRegularUserReq()
{
return makeExpectedReq(CalciteTests.REGULAR_USER_AUTH_RESULT);
}

private HttpServletRequest makeExpectedReq(AuthenticationResult authenticationResult)
{
HttpServletRequest req = EasyMock.createStrictMock(HttpServletRequest.class);
EasyMock.expect(req.getRemoteAddr()).andReturn(null).once();
EasyMock.expect(req.getAttribute(AuthConfig.DRUID_AUTHENTICATION_RESULT))
.andReturn(CalciteTests.REGULAR_USER_AUTH_RESULT)
.andReturn(authenticationResult)
.anyTimes();
EasyMock.expect(req.getAttribute(AuthConfig.DRUID_ALLOW_UNSECURED_PATH)).andReturn(null).anyTimes();
EasyMock.expect(req.getAttribute(AuthConfig.DRUID_AUTHORIZATION_CHECKED))
.andReturn(null)
.anyTimes();
EasyMock.expect(req.getAttribute(AuthConfig.DRUID_AUTHENTICATION_RESULT))
.andReturn(CalciteTests.REGULAR_USER_AUTH_RESULT)
.andReturn(authenticationResult)
.anyTimes();
req.setAttribute(AuthConfig.DRUID_AUTHORIZATION_CHECKED, true);
EasyMock.expectLastCall().anyTimes();
EasyMock.expect(req.getAttribute(AuthConfig.DRUID_AUTHENTICATION_RESULT))
.andReturn(CalciteTests.REGULAR_USER_AUTH_RESULT)
.andReturn(authenticationResult)
.anyTimes();
EasyMock.replay(req);
return req;
Expand Down

0 comments on commit 0cbd71e

Please sign in to comment.