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.query.TableDataSource;
import io.druid.server.http.security.DatasourceResourceFilter; import io.druid.server.http.security.DatasourceResourceFilter;
import io.druid.server.security.AuthConfig; import io.druid.server.security.AuthConfig;
import io.druid.server.security.AuthenticationResult;
import io.druid.server.security.AuthorizerMapper; import io.druid.server.security.AuthorizerMapper;
import io.druid.timeline.DataSegment; import io.druid.timeline.DataSegment;
import io.druid.timeline.TimelineLookup; import io.druid.timeline.TimelineLookup;
@ -110,9 +109,9 @@ public class DatasourcesResource
{ {
Response.ResponseBuilder builder = Response.ok(); Response.ResponseBuilder builder = Response.ok();
final Set<DruidDataSource> datasources = InventoryViewUtils.getSecuredDataSources( final Set<DruidDataSource> datasources = InventoryViewUtils.getSecuredDataSources(
req,
serverInventoryView, serverInventoryView,
authorizerMapper, authorizerMapper
(AuthenticationResult) req.getAttribute(AuthConfig.DRUID_AUTHENTICATION_RESULT)
); );
if (full != null) { 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.MapUtils;
import io.druid.java.util.common.guava.Comparators; import io.druid.java.util.common.guava.Comparators;
import io.druid.server.security.AuthConfig; import io.druid.server.security.AuthConfig;
import io.druid.server.security.AuthenticationResult;
import io.druid.server.security.AuthorizerMapper; import io.druid.server.security.AuthorizerMapper;
import io.druid.timeline.DataSegment; import io.druid.timeline.DataSegment;
import org.joda.time.Interval; import org.joda.time.Interval;
@ -72,9 +71,9 @@ public class IntervalsResource
{ {
final Comparator<Interval> comparator = Comparators.inverse(Comparators.intervalsByStartThenEnd()); final Comparator<Interval> comparator = Comparators.inverse(Comparators.intervalsByStartThenEnd());
final Set<DruidDataSource> datasources = InventoryViewUtils.getSecuredDataSources( final Set<DruidDataSource> datasources = InventoryViewUtils.getSecuredDataSources(
req,
serverInventoryView, serverInventoryView,
authorizerMapper, authorizerMapper
(AuthenticationResult) req.getAttribute(AuthConfig.DRUID_AUTHENTICATION_RESULT)
); );
final Map<Interval, Map<String, Map<String, Object>>> retVal = Maps.newTreeMap(comparator); 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 Interval theInterval = Intervals.of(interval.replace("_", "/"));
final Set<DruidDataSource> datasources = InventoryViewUtils.getSecuredDataSources( final Set<DruidDataSource> datasources = InventoryViewUtils.getSecuredDataSources(
req,
serverInventoryView, serverInventoryView,
authorizerMapper, authorizerMapper
(AuthenticationResult) req.getAttribute(AuthConfig.DRUID_AUTHENTICATION_RESULT)
); );
final Comparator<Interval> comparator = Comparators.inverse(Comparators.intervalsByStartThenEnd()); final Comparator<Interval> comparator = Comparators.inverse(Comparators.intervalsByStartThenEnd());

View File

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

View File

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

View File

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