Skip to content

Commit

Permalink
Feature/filter user ops (#2186)
Browse files Browse the repository at this point in the history
* Added a preInitialization method to the query logic (default noop) that
allows the infrastructure to pass info that may be used to filter when
getting the logic user operations.
  • Loading branch information
ivakegg committed Dec 13, 2023
1 parent b3b5504 commit b87543b
Show file tree
Hide file tree
Showing 12 changed files with 95 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -356,4 +356,9 @@ public void validate(Map<String,List<String>> parameters) throws IllegalArgument
public UserOperations getUserOperations() {
return delegate.getUserOperations();
}

@Override
public void preInitialize(Query settings, Set<Authorizations> queryAuths) {
delegate.preInitialize(settings, queryAuths);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -433,4 +433,15 @@ default long getResultLimit(Query settings) {
* @return A user operations interface implementation. Null if NA (i.e. the local principal is sufficient)
*/
UserOperations getUserOperations();

/**
* This is to be used prior to requesting user operations for a logic that is not yet initialized. The main use case is for the FilteredQueryLogic to allow
* it to filter this call as well. Most query logics will not implement this.
*
* @param settings
* @param userAuthorizations
*/
default void preInitialize(Query settings, Set<Authorizations> userAuthorizations) {
// noop
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.security.Principal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
Expand Down Expand Up @@ -225,6 +226,7 @@ public Set<Authorizations> updateRuntimeAuthorizationsAndQueryAuths(QueryLogic<?
if (userOperations != null) {
principal = userOperations.getRemoteUser(principal);
}
logic.preInitialize(settings, AuthorizationsUtil.buildAuthorizations(Collections.singleton(requestedAuths)));
if (logic.getUserOperations() != null) {
queryPrincipal = logic.getUserOperations().getRemoteUser(queryPrincipal);
}
Expand Down Expand Up @@ -512,6 +514,13 @@ public void setQueryLogics(Map<String,QueryLogic<?>> queryLogics) {
this.queryLogics = new TreeMap<>(queryLogics);
}

@Override
public void preInitialize(Query settings, Set<Authorizations> queryAuths) {
for (QueryLogic logic : getUninitializedLogics().values()) {
logic.preInitialize(settings, queryAuths);
}
}

public UserOperations getUserOperations() {
// if any of the underlying logics have a non-null user operations, then
// we need to return an instance that combines auths across the underlying
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@ public interface QueryLogicFilter {
boolean canRunQuery(Query settings, Set<Authorizations> auths);
}

@Override
public void preInitialize(Query settings, Set<Authorizations> userAuthorizations) {
// setup the filter
if (canRunQuery(settings, userAuthorizations)) {
super.preInitialize(settings, userAuthorizations);
}
}

public boolean canRunQuery(Query settings, Set<Authorizations> runtimeQueryAuthorizations) {
if (!filtered) {
if (!filter.canRunQuery(settings, runtimeQueryAuthorizations)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -897,6 +897,11 @@ public GenericResponse<String> planQuery(@Required("logicName") @PathParam("logi
}

// the query principal is our local principal unless the query logic has a different user operations
if (qp.getAuths() != null) {
qd.logic.preInitialize(q, AuthorizationsUtil.buildAuthorizations(Collections.singleton(AuthorizationsUtil.splitAuths(qp.getAuths()))));
} else {
qd.logic.preInitialize(q, AuthorizationsUtil.buildAuthorizations(null));
}
DatawavePrincipal queryPrincipal = (qd.logic.getUserOperations() == null) ? (DatawavePrincipal) qd.p
: qd.logic.getUserOperations().getRemoteUser((DatawavePrincipal) qd.p);
// the overall principal (the one with combined auths across remote user operations) is our own user operations bean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@ public RunningQuery(QueryMetricsBean queryMetrics, AccumuloClient client, Accumu
this.connectionPriority = priority;
this.settings = settings;
// the query principal is our local principal unless the query logic has a different user operations
if (methodAuths != null) {
logic.preInitialize(settings, AuthorizationsUtil.buildAuthorizations(Collections.singleton(AuthorizationsUtil.splitAuths(methodAuths))));
} else {
logic.preInitialize(settings, AuthorizationsUtil.buildAuthorizations(null));
}
DatawavePrincipal queryPrincipal = (logic.getUserOperations() == null) ? (DatawavePrincipal) principal
: logic.getUserOperations().getRemoteUser((DatawavePrincipal) principal);
// the overall principal (the one with combined auths across remote user operations) is our own user operations (probably the UserOperationsBean)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import datawave.webservice.common.audit.AuditParameters;
import datawave.webservice.common.exception.DatawaveWebApplicationException;
import datawave.webservice.common.exception.NoResultsException;
import datawave.webservice.query.Query;
import datawave.webservice.query.QueryParameters;
import datawave.webservice.query.QueryParametersImpl;
import datawave.webservice.query.QueryPersistence;
Expand Down Expand Up @@ -358,7 +359,7 @@ public <T> T createUUIDQueryAndNext(final AbstractUUIDLookupCriteria unvalidated
// Override the extraneous query details
String logicName = queryParameters.getFirst(QueryParameters.QUERY_LOGIC_NAME);
String queryAuths = queryParameters.getFirst(QueryParameters.QUERY_AUTHORIZATIONS);
String userAuths = getAuths(logicName, queryAuths, principal);
String userAuths = getAuths(logicName, queryParameters, queryAuths, principal);
if (queryParameters.containsKey(QueryParameters.QUERY_AUTHORIZATIONS)) {
queryParameters.remove(QueryParameters.QUERY_AUTHORIZATIONS);
}
Expand Down Expand Up @@ -429,10 +430,29 @@ public <T> T createUUIDQueryAndNext(final AbstractUUIDLookupCriteria unvalidated
return response;
}

private String getAuths(String logicName, String queryAuths, Principal principal) {
private Query createSettings(MultivaluedMap<String,String> queryParameters) {
Query query = responseObjectFactory.getQueryImpl();
if (queryParameters != null) {
query.setOptionalQueryParameters(queryParameters);
for (String key : queryParameters.keySet()) {
if (queryParameters.get(key).size() == 1) {
query.addParameter(key, queryParameters.get(key).get(0));
}
}
}
return query;
}

private String getAuths(String logicName, MultivaluedMap<String,String> queryParameters, String queryAuths, Principal principal) {
String userAuths;
try {
QueryLogic<?> logic = queryLogicFactory.getQueryLogic(logicName, principal);
Query settings = createSettings(queryParameters);
if (queryAuths == null) {
logic.preInitialize(settings, AuthorizationsUtil.buildAuthorizations(null));
} else {
logic.preInitialize(settings, AuthorizationsUtil.buildAuthorizations(Collections.singleton(AuthorizationsUtil.splitAuths(queryAuths))));
}
// the query principal is our local principal unless the query logic has a different user operations
DatawavePrincipal queryPrincipal = (logic.getUserOperations() == null) ? (DatawavePrincipal) principal
: logic.getUserOperations().getRemoteUser((DatawavePrincipal) principal);
Expand Down Expand Up @@ -584,7 +604,7 @@ private <T> T lookupContentByEvents(final AbstractUUIDLookupCriteria criteria, f
String sid = principal.getName();

// Initialize the reusable query input
final String userAuths = getAuths(CONTENT_QUERY, null, principal);
final String userAuths = getAuths(CONTENT_QUERY, criteria.getQueryParameters(), null, principal);
final String queryName = sid + '-' + UUID.randomUUID();
final Date endDate = new Date();
final Date expireDate = new Date(endDate.getTime() + 1000 * 60 * 60);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.powermock.modules.junit4.PowerMockRunner;

import datawave.microservice.querymetric.QueryMetricFactoryImpl;
import datawave.security.util.AuthorizationsUtil;
import datawave.webservice.common.connection.AccumuloConnectionFactory;
import datawave.webservice.query.QueryImpl;
import datawave.webservice.query.logic.QueryLogic;
Expand Down Expand Up @@ -125,6 +126,7 @@ public void testGetRunningQueries() throws Exception {
expect(logic.isLongRunningQuery()).andReturn(false);
expect(logic.getResultLimit(q)).andReturn(-1L);
expect(logic.getMaxResults()).andReturn(-1L);
logic.preInitialize(q, AuthorizationsUtil.buildAuthorizations(null));
expect(logic.getUserOperations()).andReturn(null);

PowerMock.replayAll();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@

import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;

import datawave.marking.ColumnVisibilitySecurityMarking;
import datawave.marking.SecurityMarking;
Expand All @@ -74,6 +75,7 @@
import datawave.security.authorization.SubjectIssuerDNPair;
import datawave.security.authorization.UserOperations;
import datawave.security.user.UserOperationsBean;
import datawave.security.util.AuthorizationsUtil;
import datawave.webservice.common.audit.AuditBean;
import datawave.webservice.common.audit.AuditParameters;
import datawave.webservice.common.audit.Auditor.AuditType;
Expand Down Expand Up @@ -375,6 +377,7 @@ public void testAdminCancel_LookupAccumuloQuery() throws Exception {
expect(this.queryLogic1.getCollectQueryMetrics()).andReturn(false);
expect(this.queryLogic1.getResultLimit(this.query)).andReturn(-1L);
expect(this.queryLogic1.getMaxResults()).andReturn(-1L);
this.queryLogic1.preInitialize(this.query, AuthorizationsUtil.buildAuthorizations(Collections.singleton(Sets.newHashSet("AUTH_2", "AUTH_1"))));
expect(this.queryLogic1.getUserOperations()).andReturn(null);
cache.put(eq(queryId.toString()), isA(RunningQuery.class));
cache.remove(queryId.toString());
Expand Down Expand Up @@ -772,6 +775,7 @@ public void testCreateQueryAndNext_HappyPath() throws Exception {
expect(this.query.getDnList()).andReturn(dnList).anyTimes();
expect(this.queryLogic1.getResultLimit(this.query)).andReturn(-1L);
expect(this.queryLogic1.getMaxResults()).andReturn(-1L);
this.queryLogic1.preInitialize(this.query, AuthorizationsUtil.buildAuthorizations(Collections.singleton(Sets.newHashSet("AUTH_1"))));
expect(this.queryLogic1.getUserOperations()).andReturn(null);
expect(this.queryLogic1.initialize(eq(this.client), eq(this.query), isA(Set.class))).andReturn(this.genericConfiguration);
this.queryLogic1.setupQuery(this.genericConfiguration);
Expand Down Expand Up @@ -948,6 +952,7 @@ public void testCreateQueryAndNext_BadID() throws Exception {
expect(this.query.getDnList()).andReturn(dnList).anyTimes();
expect(this.queryLogic1.getResultLimit(this.query)).andReturn(-1L);
expect(this.queryLogic1.getMaxResults()).andReturn(-1L);
this.queryLogic1.preInitialize(this.query, AuthorizationsUtil.buildAuthorizations(Collections.singleton(Sets.newHashSet("AUTH_1"))));
expect(this.queryLogic1.getUserOperations()).andReturn(null);
expect(this.queryLogic1.initialize(eq(this.client), eq(this.query), isA(Set.class))).andReturn(this.genericConfiguration);
this.queryLogic1.setupQuery(this.genericConfiguration);
Expand Down Expand Up @@ -1456,6 +1461,7 @@ public void testCreateQueryAndNext_DoubleAuditValues() throws Exception {
expect(this.queryLogic1.isLongRunningQuery()).andReturn(false);
expect(this.queryLogic1.getResultLimit(this.query)).andReturn(-1L);
expect(this.queryLogic1.getMaxResults()).andReturn(-1L);
this.queryLogic1.preInitialize(this.query, AuthorizationsUtil.buildAuthorizations(Collections.singleton(Sets.newHashSet("AUTH_1"))));
expect(this.queryLogic1.getUserOperations()).andReturn(null);
expect(this.queryLogic1.initialize(eq(this.client), eq(this.query), isA(Set.class))).andReturn(this.genericConfiguration);
this.queryLogic1.setupQuery(this.genericConfiguration);
Expand Down Expand Up @@ -1792,6 +1798,7 @@ public void testCreateQueryAndNext_ButNoResults() throws Exception {

expect(this.runningQuery.getLogic()).andReturn((QueryLogic) this.queryLogic1);
expect(this.queryLogic1.getCollectQueryMetrics()).andReturn(true);
this.queryLogic1.preInitialize(this.query, AuthorizationsUtil.buildAuthorizations(Collections.singleton(Sets.newHashSet("AUTH_1"))));
expect(this.queryLogic1.getUserOperations()).andReturn(null);

this.metrics.updateMetric(this.queryMetric);
Expand Down Expand Up @@ -2804,6 +2811,7 @@ public void testList_HappyPath() throws Exception {
expect(this.query.getDnList()).andReturn(dnList).anyTimes();
expect(this.queryLogic1.getResultLimit(this.query)).andReturn(-1L);
expect(this.queryLogic1.getMaxResults()).andReturn(-1L);
this.queryLogic1.preInitialize(this.query, AuthorizationsUtil.buildAuthorizations(null));
expect(this.queryLogic1.getUserOperations()).andReturn(null);
this.cache.put(eq(queryId.toString()), isA(RunningQuery.class));

Expand Down Expand Up @@ -3309,6 +3317,7 @@ public void testReset_NoPreexistingRunningQuery() throws Exception {
expect(this.queryLogic1.isLongRunningQuery()).andReturn(false);
expect(this.queryLogic1.getResultLimit(this.query)).andReturn(-1L);
expect(this.queryLogic1.getMaxResults()).andReturn(-1L);
this.queryLogic1.preInitialize(this.query, AuthorizationsUtil.buildAuthorizations(Collections.singleton(Sets.newHashSet("AUTH_1"))));
expect(this.queryLogic1.getUserOperations()).andReturn(null);
expect(this.query.toMap()).andReturn(map);
expect(this.query.getColumnVisibility()).andReturn(authorization);
Expand Down Expand Up @@ -3892,6 +3901,7 @@ public void testPlanQuery() throws Exception {
expect(this.dwUser.getAuths()).andReturn(Collections.singleton(queryAuthorizations)).anyTimes();
expect(this.principal.getProxiedUsers()).andReturn(Collections.singletonList(dwUser));
expect(this.userOperations.getRemoteUser(this.principal)).andReturn(this.principal);
this.queryLogic1.preInitialize(this.query, AuthorizationsUtil.buildAuthorizations(Collections.singleton(Sets.newHashSet("AUTH_1"))));
expect(this.queryLogic1.getUserOperations()).andReturn(null);
expect(this.query.getOwner()).andReturn(userSid).anyTimes();
expect(this.query.getId()).andReturn(queryId).anyTimes();
Expand Down Expand Up @@ -4022,6 +4032,7 @@ public void testPlanQueryWithValues() throws Exception {
expect(this.queryLogic1.getAuditType(this.query)).andReturn(AuditType.PASSIVE);
expect(this.queryLogic1.getConnectionPriority()).andReturn(Priority.NORMAL);
expect(this.queryLogic1.getConnPoolName()).andReturn("connPool1");
this.queryLogic1.preInitialize(this.query, AuthorizationsUtil.buildAuthorizations(Collections.singleton(Sets.newHashSet("AUTH_1"))));
expect(this.queryLogic1.getUserOperations()).andReturn(null);
expect(this.connectionFactory.getTrackingMap(isA(StackTraceElement[].class))).andReturn(null);
this.query.populateTrackingMap(null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import datawave.security.authorization.DatawaveUser;
import datawave.security.authorization.DatawaveUser.UserType;
import datawave.security.authorization.SubjectIssuerDNPair;
import datawave.security.util.AuthorizationsUtil;
import datawave.security.util.DnUtils.NpeUtils;
import datawave.webservice.common.connection.AccumuloConnectionFactory;
import datawave.webservice.common.connection.AccumuloConnectionFactory.Priority;
Expand Down Expand Up @@ -180,6 +181,7 @@ public void testNext_HappyPathUsingDeprecatedConstructor() throws Exception {
expect(this.genericConfiguration.getQueryString()).andReturn(query).once();
expect(this.queryLogic.isLongRunningQuery()).andReturn(false);
expect(this.queryLogic.getResultLimit(eq(this.query))).andReturn(maxResults);
this.queryLogic.preInitialize(this.query, AuthorizationsUtil.buildAuthorizations(Collections.singleton(Collections.singleton("AUTH_1"))));
expect(this.queryLogic.getUserOperations()).andReturn(null);
this.queryLogic.setPageProcessingStartTime(anyLong());

Expand Down Expand Up @@ -270,6 +272,7 @@ public void testNextMaxResults_HappyPathUsingDeprecatedConstructor() throws Exce
expect(this.queryLogic.getPageByteTrigger()).andReturn(pageByteTrigger).anyTimes();
expect(this.queryLogic.getMaxWork()).andReturn(maxWork).anyTimes();
expect(this.queryLogic.getMaxResults()).andReturn(maxResults).anyTimes();
this.queryLogic.preInitialize(this.query, AuthorizationsUtil.buildAuthorizations(Collections.singleton(Collections.singleton("AUTH_1"))));
expect(this.queryLogic.getUserOperations()).andReturn(null);
expect(this.genericConfiguration.getQueryString()).andReturn(query).once();
this.queryLogic.setPageProcessingStartTime(anyLong());
Expand Down Expand Up @@ -339,6 +342,7 @@ public void testNext_NoResultsAfterCancellationUsingDeprecatedConstructor() thro
expect(this.queryLogic.isLongRunningQuery()).andReturn(false);
expect(this.queryLogic.getResultLimit(eq(this.query))).andReturn(maxResults);
expect(this.queryLogic.getMaxResults()).andReturn(maxResults);
this.queryLogic.preInitialize(this.query, AuthorizationsUtil.buildAuthorizations(Collections.singleton(Collections.singleton("AUTH_1"))));
expect(this.queryLogic.getUserOperations()).andReturn(null);
this.queryLogic.setPageProcessingStartTime(anyLong());

Expand Down Expand Up @@ -393,6 +397,7 @@ public void testCloseConnection_HappyPath() throws Exception {
expect(this.queryLogic.isLongRunningQuery()).andReturn(false);
expect(this.queryLogic.getResultLimit(eq(this.query))).andReturn(maxResults);
expect(this.queryLogic.getMaxResults()).andReturn(maxResults);
this.queryLogic.preInitialize(this.query, AuthorizationsUtil.buildAuthorizations(Collections.singleton(Collections.singleton("AUTH_1"))));
expect(this.queryLogic.getUserOperations()).andReturn(null);
this.queryLogic.setupQuery(this.genericConfiguration);
this.queryMetrics.updateMetric(isA(QueryMetric.class));
Expand Down Expand Up @@ -481,6 +486,7 @@ public void testNextWithDnResultLimit_HappyPathUsingDeprecatedConstructor() thro
expect(this.queryLogic.getPageByteTrigger()).andReturn(pageByteTrigger).anyTimes();
expect(this.queryLogic.getMaxWork()).andReturn(maxWork).anyTimes();
expect(this.queryLogic.getMaxResults()).andReturn(maxResults).anyTimes();
this.queryLogic.preInitialize(this.query, AuthorizationsUtil.buildAuthorizations(Collections.singleton(Collections.singleton("AUTH_1"))));
expect(this.queryLogic.getUserOperations()).andReturn(null);
expect(this.genericConfiguration.getQueryString()).andReturn(query).once();
this.queryLogic.setPageProcessingStartTime(anyLong());
Expand Down
Loading

0 comments on commit b87543b

Please sign in to comment.