Fix auth check in InventoryViewUtils (#4869)

This commit is contained in:
Jonathan Wei 2017-10-02 11:38:45 -07:00 committed by Gian Merlino
parent 3e9391433d
commit 9deab26d8b
5 changed files with 92 additions and 65 deletions

View File

@ -43,7 +43,6 @@ import io.druid.metadata.MetadataSegmentManager;
import io.druid.query.TableDataSource;
import io.druid.server.http.security.DatasourceResourceFilter;
import io.druid.server.security.AuthConfig;
import io.druid.server.security.AuthenticationResult;
import io.druid.server.security.AuthorizerMapper;
import io.druid.timeline.DataSegment;
import io.druid.timeline.TimelineLookup;
@ -110,9 +109,9 @@ public class DatasourcesResource
{
Response.ResponseBuilder builder = Response.ok();
final Set<DruidDataSource> datasources = InventoryViewUtils.getSecuredDataSources(
req,
serverInventoryView,
authorizerMapper,
(AuthenticationResult) req.getAttribute(AuthConfig.DRUID_AUTHENTICATION_RESULT)
authorizerMapper
);
if (full != null) {

View File

@ -27,7 +27,6 @@ import io.druid.java.util.common.Intervals;
import io.druid.java.util.common.MapUtils;
import io.druid.java.util.common.guava.Comparators;
import io.druid.server.security.AuthConfig;
import io.druid.server.security.AuthenticationResult;
import io.druid.server.security.AuthorizerMapper;
import io.druid.timeline.DataSegment;
import org.joda.time.Interval;
@ -72,9 +71,9 @@ public class IntervalsResource
{
final Comparator<Interval> comparator = Comparators.inverse(Comparators.intervalsByStartThenEnd());
final Set<DruidDataSource> datasources = InventoryViewUtils.getSecuredDataSources(
req,
serverInventoryView,
authorizerMapper,
(AuthenticationResult) req.getAttribute(AuthConfig.DRUID_AUTHENTICATION_RESULT)
authorizerMapper
);
final Map<Interval, Map<String, Map<String, Object>>> retVal = Maps.newTreeMap(comparator);
@ -104,9 +103,9 @@ public class IntervalsResource
{
final Interval theInterval = Intervals.of(interval.replace("_", "/"));
final Set<DruidDataSource> datasources = InventoryViewUtils.getSecuredDataSources(
req,
serverInventoryView,
authorizerMapper,
(AuthenticationResult) req.getAttribute(AuthConfig.DRUID_AUTHENTICATION_RESULT)
authorizerMapper
);
final Comparator<Interval> comparator = Comparators.inverse(Comparators.intervalsByStartThenEnd());

View File

@ -20,7 +20,6 @@
package io.druid.server.http;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
@ -30,18 +29,11 @@ import io.druid.client.DruidDataSource;
import io.druid.client.DruidServer;
import io.druid.client.InventoryView;
import io.druid.java.util.common.ISE;
import io.druid.java.util.common.Pair;
import io.druid.server.security.Access;
import io.druid.server.security.Action;
import io.druid.server.security.AuthenticationResult;
import io.druid.server.security.Authorizer;
import io.druid.server.security.AuthorizationUtils;
import io.druid.server.security.AuthorizerMapper;
import io.druid.server.security.Resource;
import io.druid.server.security.ResourceType;
import javax.servlet.http.HttpServletRequest;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
@ -81,42 +73,26 @@ public class InventoryViewUtils
}
public static Set<DruidDataSource> getSecuredDataSources(
HttpServletRequest request,
InventoryView inventoryView,
final AuthorizerMapper authorizerMapper,
final AuthenticationResult authenticationResult
final AuthorizerMapper authorizerMapper
)
{
if (authorizerMapper == null) {
throw new ISE("No authorization mapper found");
}
final Authorizer authorizer = authorizerMapper.getAuthorizer(authenticationResult.getAuthorizerName());
if (authorizer == null) {
throw new ISE("Invalid to call a secured method with null Authorizer!!");
} else {
final Map<Pair<Resource, Action>, Access> resourceAccessMap = new HashMap<>();
return ImmutableSet.copyOf(
Iterables.filter(
getDataSources(inventoryView),
new Predicate<DruidDataSource>()
{
@Override
public boolean apply(DruidDataSource input)
{
Resource resource = new Resource(input.getName(), ResourceType.DATASOURCE);
Action action = Action.READ;
Pair<Resource, Action> key = new Pair<>(resource, action);
if (resourceAccessMap.containsKey(key)) {
return resourceAccessMap.get(key).isAllowed();
} else {
Access access = authorizer.authorize(authenticationResult, key.lhs, key.rhs);
resourceAccessMap.put(key, access);
return access.isAllowed();
}
}
}
)
);
}
return ImmutableSet.copyOf(
AuthorizationUtils.filterAuthorizedResources(
request,
getDataSources(inventoryView),
datasource -> {
return Lists.newArrayList(
AuthorizationUtils.DATASOURCE_READ_RA_GENERATOR.apply(datasource.getName())
);
},
authorizerMapper
)
);
}
}

View File

@ -118,15 +118,34 @@ public class DatasourcesResourceTest
@Test
public void testGetFullQueryableDataSources() throws Exception
{
// first request
EasyMock.expect(server.getDataSources()).andReturn(
ImmutableList.of(listDataSources.get(0), listDataSources.get(1))
).atLeastOnce();
).once();
EasyMock.expect(inventoryView.getInventory()).andReturn(
ImmutableList.of(server)
).atLeastOnce();
).once();
EasyMock.expect(request.getAttribute(AuthConfig.DRUID_AUTHORIZATION_CHECKED)).andReturn(null).once();
EasyMock.expect(request.getAttribute(AuthConfig.DRUID_AUTHENTICATION_RESULT)).andReturn(
new AuthenticationResult("druid", "druid")
).atLeastOnce();
new AuthenticationResult("druid", "druid")
).once();
request.setAttribute(AuthConfig.DRUID_AUTHORIZATION_CHECKED, true);
EasyMock.expectLastCall().times(1);
// second request
EasyMock.expect(server.getDataSources()).andReturn(
ImmutableList.of(listDataSources.get(0), listDataSources.get(1))
).once();
EasyMock.expect(inventoryView.getInventory()).andReturn(
ImmutableList.of(server)
).once();
EasyMock.expect(request.getAttribute(AuthConfig.DRUID_AUTHORIZATION_CHECKED)).andReturn(null).once();
EasyMock.expect(request.getAttribute(AuthConfig.DRUID_AUTHENTICATION_RESULT)).andReturn(
new AuthenticationResult("druid", "druid")
).once();
request.setAttribute(AuthConfig.DRUID_AUTHORIZATION_CHECKED, true);
EasyMock.expectLastCall().times(1);
EasyMock.replay(inventoryView, server, request);
DatasourcesResource datasourcesResource = new DatasourcesResource(
inventoryView,
@ -155,18 +174,37 @@ public class DatasourcesResourceTest
@Test
public void testSecuredGetFullQueryableDataSources() throws Exception
{
AuthenticationResult authenticationResult = new AuthenticationResult("druid", "druid");
EasyMock.expect(request.getAttribute(AuthConfig.DRUID_AUTHENTICATION_RESULT))
.andReturn(authenticationResult)
.anyTimes();
// first request
EasyMock.expect(server.getDataSources()).andReturn(
ImmutableList.of(listDataSources.get(0), listDataSources.get(1))
).atLeastOnce();
ImmutableList.of(listDataSources.get(0), listDataSources.get(1))
).once();
EasyMock.expect(request.getAttribute(AuthConfig.DRUID_AUTHORIZATION_CHECKED)).andReturn(null).once();
EasyMock.expect(request.getAttribute(AuthConfig.DRUID_AUTHENTICATION_RESULT)).andReturn(
new AuthenticationResult("druid", "druid")
).once();
request.setAttribute(AuthConfig.DRUID_AUTHORIZATION_CHECKED, true);
EasyMock.expectLastCall().times(1);
EasyMock.expect(inventoryView.getInventory()).andReturn(
ImmutableList.of(server)
).atLeastOnce();
).once();
// second request
EasyMock.expect(server.getDataSources()).andReturn(
ImmutableList.of(listDataSources.get(0), listDataSources.get(1))
).once();
EasyMock.expect(request.getAttribute(AuthConfig.DRUID_AUTHORIZATION_CHECKED)).andReturn(null).once();
EasyMock.expect(request.getAttribute(AuthConfig.DRUID_AUTHENTICATION_RESULT)).andReturn(
new AuthenticationResult("druid", "druid")
).once();
request.setAttribute(AuthConfig.DRUID_AUTHORIZATION_CHECKED, true);
EasyMock.expectLastCall().times(1);
EasyMock.expect(inventoryView.getInventory()).andReturn(
ImmutableList.of(server)
).once();
EasyMock.replay(inventoryView, server, request);
AuthorizerMapper authMapper = new AuthorizerMapper(null) {
@ -232,9 +270,12 @@ public class DatasourcesResourceTest
EasyMock.expect(inventoryView.getInventory()).andReturn(
ImmutableList.of(server)
).atLeastOnce();
EasyMock.expect(request.getAttribute(AuthConfig.DRUID_AUTHORIZATION_CHECKED)).andReturn(null).once();
EasyMock.expect(request.getAttribute(AuthConfig.DRUID_AUTHENTICATION_RESULT)).andReturn(
new AuthenticationResult("druid", "druid")
).atLeastOnce();
).once();
request.setAttribute(AuthConfig.DRUID_AUTHORIZATION_CHECKED, true);
EasyMock.expectLastCall().times(1);
EasyMock.replay(inventoryView, server, request);
DatasourcesResource datasourcesResource = new DatasourcesResource(

View File

@ -108,9 +108,12 @@ public class IntervalsResourceTest
EasyMock.expect(inventoryView.getInventory()).andReturn(
ImmutableList.of(server)
).atLeastOnce();
EasyMock.expect(request.getAttribute(AuthConfig.DRUID_AUTHORIZATION_CHECKED)).andReturn(null).once();
EasyMock.expect(request.getAttribute(AuthConfig.DRUID_AUTHENTICATION_RESULT)).andReturn(
new AuthenticationResult("druid", "druid")
).atLeastOnce();
).once();
request.setAttribute(AuthConfig.DRUID_AUTHORIZATION_CHECKED, true);
EasyMock.expectLastCall().times(1);
EasyMock.replay(inventoryView, request);
List<Interval> expectedIntervals = new ArrayList<>();
@ -142,9 +145,12 @@ public class IntervalsResourceTest
EasyMock.expect(inventoryView.getInventory()).andReturn(
ImmutableList.of(server)
).atLeastOnce();
EasyMock.expect(request.getAttribute(AuthConfig.DRUID_AUTHORIZATION_CHECKED)).andReturn(null).once();
EasyMock.expect(request.getAttribute(AuthConfig.DRUID_AUTHENTICATION_RESULT)).andReturn(
new AuthenticationResult("druid", "druid")
).atLeastOnce();
).once();
request.setAttribute(AuthConfig.DRUID_AUTHORIZATION_CHECKED, true);
EasyMock.expectLastCall().times(1);
EasyMock.replay(inventoryView, request);
List<Interval> expectedIntervals = new ArrayList<>();
@ -170,9 +176,12 @@ public class IntervalsResourceTest
EasyMock.expect(inventoryView.getInventory()).andReturn(
ImmutableList.of(server)
).atLeastOnce();
EasyMock.expect(request.getAttribute(AuthConfig.DRUID_AUTHORIZATION_CHECKED)).andReturn(null).once();
EasyMock.expect(request.getAttribute(AuthConfig.DRUID_AUTHENTICATION_RESULT)).andReturn(
new AuthenticationResult("druid", "druid")
).atLeastOnce();
).once();
request.setAttribute(AuthConfig.DRUID_AUTHORIZATION_CHECKED, true);
EasyMock.expectLastCall().times(1);
EasyMock.replay(inventoryView, request);
List<Interval> expectedIntervals = new ArrayList<>();
@ -200,9 +209,12 @@ public class IntervalsResourceTest
EasyMock.expect(inventoryView.getInventory()).andReturn(
ImmutableList.of(server)
).atLeastOnce();
EasyMock.expect(request.getAttribute(AuthConfig.DRUID_AUTHORIZATION_CHECKED)).andReturn(null).once();
EasyMock.expect(request.getAttribute(AuthConfig.DRUID_AUTHENTICATION_RESULT)).andReturn(
new AuthenticationResult("druid", "druid")
).atLeastOnce();
).once();
request.setAttribute(AuthConfig.DRUID_AUTHORIZATION_CHECKED, true);
EasyMock.expectLastCall().times(1);
EasyMock.replay(inventoryView, request);
IntervalsResource intervalsResource = new IntervalsResource(