use of datawave.security.authorization.DatawavePrincipal in project datawave by NationalSecurityAgency.
the class QueryExecutorBeanTest method testCreateWithNoSelectedAuths.
@SuppressWarnings("unchecked")
@Test(expected = DatawaveWebApplicationException.class)
public void testCreateWithNoSelectedAuths() throws Exception {
String queryLogicName = "EventQueryLogic";
String queryName = "Something";
String query = "FOO == BAR";
Date beginDate = new Date();
Date expirationDate = DateUtils.addDays(new Date(), 1);
int pagesize = 10;
QueryPersistence persist = QueryPersistence.TRANSIENT;
Set<QueryImpl.Parameter> parameters = new HashSet<>();
// need to call the getQueryByName() method. Maybe a partial mock of QueryExecutorBean would be better
// setup principal mock
String userDN = "CN=Guy Some Other soguy, OU=MY_SUBDIVISION, OU=MY_DIVISION, O=ORG, C=US";
String[] auths = new String[2];
auths[0] = "PRIVATE";
auths[1] = "PUBLIC";
QueryImpl q = new QueryImpl();
q.setBeginDate(beginDate);
q.setEndDate(beginDate);
q.setExpirationDate(expirationDate);
q.setPagesize(pagesize);
q.setParameters(parameters);
q.setQuery(query);
q.setQueryAuthorizations(StringUtils.join(auths, ","));
q.setQueryLogicName(queryLogicName);
q.setUserDN(userDN);
q.setId(UUID.randomUUID());
@SuppressWarnings("rawtypes") QueryLogic logic = createMock(BaseQueryLogic.class);
MultivaluedMap<String, String> p = new MultivaluedMapImpl<>();
p.putSingle(QueryParameters.QUERY_AUTHORIZATIONS, "");
p.putSingle(QueryParameters.QUERY_BEGIN, QueryParametersImpl.formatDate(beginDate));
p.putSingle(QueryParameters.QUERY_END, QueryParametersImpl.formatDate(beginDate));
p.putSingle(QueryParameters.QUERY_EXPIRATION, QueryParametersImpl.formatDate(expirationDate));
p.putSingle(QueryParameters.QUERY_NAME, queryName);
p.putSingle(QueryParameters.QUERY_PAGESIZE, Integer.toString(pagesize));
p.putSingle(QueryParameters.QUERY_STRING, query);
p.putSingle(QueryParameters.QUERY_PERSISTENCE, persist.name());
p.putSingle(ColumnVisibilitySecurityMarking.VISIBILITY_MARKING, "PRIVATE|PUBLIC");
InMemoryInstance instance = new InMemoryInstance();
Connector c = instance.getConnector("root", new PasswordToken(""));
QueryParameters qp = new QueryParametersImpl();
MultivaluedMap<String, String> optionalParameters = new MultivaluedMapImpl<>();
optionalParameters.putAll(qp.getUnknownParameters(p));
DatawaveUser user = new DatawaveUser(SubjectIssuerDNPair.of(userDN, "<CN=MY_CA, OU=MY_SUBDIVISION, OU=MY_DIVISION, O=ORG, C=US>"), UserType.USER, Arrays.asList(auths), null, null, 0L);
DatawavePrincipal principal = new DatawavePrincipal(Collections.singletonList(user));
String[] dns = principal.getDNs();
Arrays.sort(dns);
List<String> dnList = Arrays.asList(dns);
PowerMock.resetAll();
EasyMock.expect(ctx.getCallerPrincipal()).andReturn(principal).anyTimes();
suppress(constructor(QueryParametersImpl.class));
EasyMock.expect(persister.create(userDN, dnList, (SecurityMarking) Whitebox.getField(bean.getClass(), "marking").get(bean), queryLogicName, (QueryParameters) Whitebox.getField(bean.getClass(), "qp").get(bean), optionalParameters)).andReturn(q);
EasyMock.expect(queryLogicFactory.getQueryLogic(queryLogicName, principal)).andReturn(logic);
EasyMock.expect(logic.getRequiredQueryParameters()).andReturn(Collections.EMPTY_SET);
EasyMock.expect(logic.containsDNWithAccess(dnList)).andReturn(true);
EasyMock.expect(logic.getMaxPageSize()).andReturn(0);
EasyMock.expect(logic.getAuditType(EasyMock.<Query>anyObject())).andReturn(AuditType.ACTIVE).anyTimes();
EasyMock.expect(logic.getSelectors(anyObject())).andReturn(null);
Map<String, String> auditParams = new HashMap<>();
auditParams.put(QueryParameters.QUERY_STRING, p.getFirst(QueryParameters.QUERY_STRING));
auditParams.put(AuditParameters.USER_DN, userDN);
auditParams.put(AuditParameters.QUERY_SECURITY_MARKING_COLVIZ, "PRIVATE|PUBLIC");
auditParams.put(AuditParameters.QUERY_AUDIT_TYPE, AuditType.ACTIVE.name());
auditParams.put(AuditParameters.QUERY_LOGIC_CLASS, "EventQueryLogic");
EasyMock.expect(auditService.audit(eq(auditParams))).andReturn(null);
logic.close();
EasyMock.expectLastCall();
persister.remove(anyObject(Query.class));
PowerMock.replayAll();
bean.createQuery(queryLogicName, p);
PowerMock.verifyAll();
}
use of datawave.security.authorization.DatawavePrincipal in project datawave by NationalSecurityAgency.
the class QueryExecutorBeanTest method defineTestRunner.
private void defineTestRunner(QueryImpl q, MultivaluedMap p) throws Exception {
MultivaluedMap<String, String> optionalParameters = createNewQueryParameters(q, p);
@SuppressWarnings("rawtypes") QueryLogic logic = createMock(BaseQueryLogic.class);
DatawaveUser user = new DatawaveUser(SubjectIssuerDNPair.of(userDN, "<CN=MY_CA, OU=MY_SUBDIVISION, OU=MY_DIVISION, O=ORG, C=US>"), UserType.USER, Arrays.asList(auths), null, null, 0L);
DatawavePrincipal principal = new DatawavePrincipal(Collections.singletonList(user));
String[] dns = principal.getDNs();
Arrays.sort(dns);
List<String> dnList = Arrays.asList(dns);
PowerMock.resetAll();
EasyMock.expect(ctx.getCallerPrincipal()).andReturn(principal).anyTimes();
suppress(constructor(QueryParametersImpl.class));
EasyMock.expect(persister.create(principal.getUserDN().subjectDN(), dnList, (SecurityMarking) Whitebox.getField(bean.getClass(), "marking").get(bean), queryLogicName, (QueryParameters) Whitebox.getField(bean.getClass(), "qp").get(bean), optionalParameters)).andReturn(q);
EasyMock.expect(queryLogicFactory.getQueryLogic(queryLogicName, principal)).andReturn(logic);
EasyMock.expect(logic.getRequiredQueryParameters()).andReturn(Collections.EMPTY_SET);
EasyMock.expect(logic.getConnectionPriority()).andReturn(AccumuloConnectionFactory.Priority.NORMAL);
EasyMock.expect(logic.containsDNWithAccess(dnList)).andReturn(true);
EasyMock.expect(logic.getMaxPageSize()).andReturn(0);
EasyMock.expect(logic.getCollectQueryMetrics()).andReturn(Boolean.FALSE);
EasyMock.expect(logic.getResultLimit(q.getDnList())).andReturn(-1L);
EasyMock.expect(logic.getMaxResults()).andReturn(-1L);
PowerMock.replayAll();
bean.defineQuery(queryLogicName, p);
PowerMock.verifyAll();
Object cachedRunningQuery = cache.get(q.getId().toString());
Assert.assertNotNull(cachedRunningQuery);
RunningQuery rq2 = (RunningQuery) cachedRunningQuery;
Assert.assertEquals(q, rq2.getSettings());
}
use of datawave.security.authorization.DatawavePrincipal in project datawave by NationalSecurityAgency.
the class QueryExecutorBeanTest method testCloseActuallyCloses.
@SuppressWarnings("unchecked")
@Test(timeout = 5000)
public void testCloseActuallyCloses() throws Exception {
QueryImpl q = createNewQuery();
final MultivaluedMap<String, String> queryParameters = createNewQueryParameterMap();
queryParameters.putSingle(QueryParameters.QUERY_LOGIC_NAME, "EventQueryLogic");
final Thread createQuery = new Thread(() -> {
try {
bean.createQuery("EventQueryLogic", queryParameters);
} catch (Exception e) {
// ok if we fail the call
log.debug("createQuery terminated with " + e);
}
});
final Throwable[] createQueryException = { null };
createQuery.setUncaughtExceptionHandler((t, e) -> createQueryException[0] = e);
@SuppressWarnings("rawtypes") QueryLogic logic = createMock(BaseQueryLogic.class);
DatawaveUser user = new DatawaveUser(SubjectIssuerDNPair.of(userDN, "<CN=MY_CA, OU=MY_SUBDIVISION, OU=MY_DIVISION, O=ORG, C=US>"), UserType.USER, Arrays.asList(auths), null, null, 0L);
DatawavePrincipal principal = new DatawavePrincipal(Collections.singletonList(user));
principal.getShortName();
String[] dns = principal.getDNs();
Arrays.sort(dns);
List<String> dnList = Arrays.asList(dns);
InMemoryInstance instance = new InMemoryInstance();
Connector c = instance.getConnector("root", new PasswordToken(""));
MultivaluedMap<String, String> optionalParameters = createNewQueryParameters(q, queryParameters);
PowerMock.resetAll();
EasyMock.expect(ctx.getCallerPrincipal()).andReturn(principal).anyTimes();
EasyMock.expect(logic.getAuditType(null)).andReturn(AuditType.NONE);
EasyMock.expect(persister.create(principal.getUserDN().subjectDN(), dnList, Whitebox.getInternalState(bean, SecurityMarking.class), queryLogicName, Whitebox.getInternalState(bean, QueryParameters.class), optionalParameters)).andReturn(q);
EasyMock.expect(persister.findById(EasyMock.anyString())).andReturn(null).anyTimes();
EasyMock.expect(connectionFactory.getTrackingMap(anyObject())).andReturn(Maps.newHashMap()).anyTimes();
BaseQueryMetric metric = new QueryMetricFactoryImpl().createMetric();
metric.populate(q);
EasyMock.expectLastCall();
metric.setQueryType(RunningQuery.class.getSimpleName());
metric.setLifecycle(Lifecycle.DEFINED);
System.out.println(metric);
Set<Prediction> predictions = new HashSet<>();
predictions.add(new Prediction("source", 1));
EasyMock.expect(predictor.predict(metric)).andReturn(predictions);
connectionRequestBean.requestBegin(q.getId().toString());
EasyMock.expectLastCall();
EasyMock.expect(connectionFactory.getConnection(eq("connPool1"), anyObject(), anyObject())).andReturn(c).anyTimes();
connectionRequestBean.requestEnd(q.getId().toString());
EasyMock.expectLastCall();
connectionFactory.returnConnection(c);
EasyMock.expectLastCall();
EasyMock.expect(queryLogicFactory.getQueryLogic(queryLogicName, principal)).andReturn(logic);
EasyMock.expect(logic.getRequiredQueryParameters()).andReturn(Collections.emptySet());
EasyMock.expect(logic.getConnectionPriority()).andReturn(AccumuloConnectionFactory.Priority.NORMAL).atLeastOnce();
EasyMock.expect(logic.containsDNWithAccess(dnList)).andReturn(true);
EasyMock.expect(logic.getMaxPageSize()).andReturn(0);
EasyMock.expect(logic.getAuditType(q)).andReturn(AuditType.NONE);
EasyMock.expect(logic.getConnPoolName()).andReturn("connPool1");
EasyMock.expect(logic.getResultLimit(eq(q.getDnList()))).andReturn(-1L).anyTimes();
EasyMock.expect(logic.getMaxResults()).andReturn(-1L).anyTimes();
EasyMock.expect(connectionRequestBean.cancelConnectionRequest(q.getId().toString(), principal)).andReturn(false).anyTimes();
connectionFactory.returnConnection(EasyMock.isA(Connector.class));
final AtomicBoolean initializeLooping = new AtomicBoolean(false);
// During initialize, mark that we get here, and then sleep
final IAnswer<GenericQueryConfiguration> initializeAnswer = () -> {
initializeLooping.set(true);
try {
while (true) {
Thread.sleep(1000);
log.debug("Initialize: woke up");
}
} catch (InterruptedException e) {
throw new QueryException("EXPECTED EXCEPTION: initialize interrupted");
}
};
EasyMock.expect(logic.initialize(anyObject(Connector.class), anyObject(Query.class), anyObject(Set.class))).andAnswer(initializeAnswer);
EasyMock.expect(logic.getCollectQueryMetrics()).andReturn(Boolean.FALSE);
// On close, interrupt the thread to simulate the ScannerFactory cleaning up
final IAnswer<Object> closeAnswer = () -> {
if (null != createQuery) {
log.debug("createQuery thread is not null. interrupting");
createQuery.interrupt();
} else {
log.debug("createQuery thread is null. not interrupting");
}
return null;
};
logic.close();
EasyMock.expectLastCall().andAnswer(closeAnswer).anyTimes();
// Make the QueryLogic mock not threadsafe, otherwise it will be blocked infinitely
// trying to get the lock on the infinite loop
EasyMock.makeThreadSafe(logic, false);
metrics.updateMetric(EasyMock.isA(QueryMetric.class));
PowerMock.replayAll();
try {
createQuery.start();
// Wait for the create call to get to initialize
while (!initializeLooping.get()) {
if (!createQuery.isAlive() && !initializeLooping.get()) {
Assert.fail("createQuery thread died before reaching initialize: " + createQueryException[0]);
}
Thread.sleep(50);
}
// initialize has not completed yet so it will not appear in the cache
Object cachedRunningQuery = cache.get(q.getId().toString());
Assert.assertNull(cachedRunningQuery);
Pair<QueryLogic<?>, Connector> pair = qlCache.poll(q.getId().toString());
Assert.assertNotNull(pair);
Assert.assertEquals(logic, pair.getFirst());
Assert.assertEquals(c, pair.getSecond());
// Have to add these back because poll was destructive
qlCache.add(q.getId().toString(), principal.getShortName(), pair.getFirst(), pair.getSecond());
// Call close
bean.close(q.getId().toString());
// Make sure that it's gone from the qlCache
pair = qlCache.poll(q.getId().toString());
Assert.assertNull("Still found an entry in the qlCache: " + pair, pair);
// Should have already joined by now, but just to be sure
createQuery.join();
} finally {
if (null != createQuery && createQuery.isAlive()) {
createQuery.interrupt();
}
}
}
use of datawave.security.authorization.DatawavePrincipal in project datawave by NationalSecurityAgency.
the class ExtendedRunningQueryTest method testNext_HappyPathUsingDeprecatedConstructor.
@SuppressWarnings({ "unchecked", "rawtypes" })
@Test
public void testNext_HappyPathUsingDeprecatedConstructor() throws Exception {
// Set local test input
String userDN = "userDN";
List<String> dnList = Lists.newArrayList(userDN);
String userSid = "userSid";
UUID queryId = UUID.randomUUID();
String methodAuths = "AUTH_1";
String columnVisibility = "AUTH_1";
DatawaveUser user = new DatawaveUser(SubjectIssuerDNPair.of("userDN", "issuerDN"), UserType.USER, Collections.singleton(methodAuths), null, null, 0L);
DatawavePrincipal principal = new DatawavePrincipal(Collections.singletonList(user));
String query = "query";
String queryLogicName = "queryLogicName";
String queryName = "queryName";
long currentTime = System.currentTimeMillis();
Date beginDate = new Date(currentTime - 5000);
Date endDate = new Date(currentTime - 1000);
Date expirationDate = new Date(currentTime + 9999);
int pageSize = 3;
int maxPageSize = 10;
long pageByteTrigger = 4 * 1024L;
long maxWork = Long.MAX_VALUE;
long maxResults = 100L;
List<Object> resultObjects = Arrays.asList(new Object(), "resultObject1", null);
// Set expectations
expect(this.queryLogic.getCollectQueryMetrics()).andReturn(true);
expect(this.query.getUncaughtExceptionHandler()).andReturn(exceptionHandler).times(5);
expect(this.exceptionHandler.getThrowable()).andReturn(null).times(5);
expect(this.query.getId()).andReturn(queryId).times(4);
expect(this.query.getOwner()).andReturn(userSid).times(2);
expect(this.query.getQuery()).andReturn(query).times(2);
expect(this.query.getQueryLogicName()).andReturn(queryLogicName).times(2);
expect(this.query.getQueryName()).andReturn(queryName).times(2);
expect(this.query.getBeginDate()).andReturn(beginDate).times(2);
expect(this.query.getEndDate()).andReturn(endDate).times(2);
expect(this.query.isMaxResultsOverridden()).andReturn(false).anyTimes();
expect(this.query.getExpirationDate()).andReturn(expirationDate);
expect(this.query.getParameters()).andReturn(new HashSet<>()).times(2);
expect(this.query.getQueryAuthorizations()).andReturn(methodAuths).times(2);
expect(this.query.getColumnVisibility()).andReturn(columnVisibility);
expect(this.query.getUserDN()).andReturn(userDN).times(3);
expect(this.query.getDnList()).andReturn(dnList);
expect(this.queryLogic.initialize(eq(this.connector), eq(this.query), isA(Set.class))).andReturn(this.genericConfiguration);
this.queryLogic.setupQuery(this.genericConfiguration);
expect(this.queryLogic.getTransformIterator(this.query)).andReturn(this.transformIterator);
Iterator<Object> iterator = resultObjects.iterator();
while (iterator.hasNext()) {
expect(this.transformIterator.hasNext()).andReturn(iterator.hasNext());
expect(this.transformIterator.next()).andReturn(iterator.next());
expect(this.transformIterator.getTransformer()).andReturn(transformer);
}
expect(this.query.getPagesize()).andReturn(pageSize).anyTimes();
expect(this.queryLogic.getMaxPageSize()).andReturn(maxPageSize).anyTimes();
expect(this.queryLogic.getPageByteTrigger()).andReturn(pageByteTrigger).anyTimes();
expect(this.queryLogic.getMaxWork()).andReturn(maxWork).anyTimes();
expect(this.queryLogic.getMaxResults()).andReturn(maxResults).anyTimes();
expect(this.genericConfiguration.getQueryString()).andReturn(query).once();
expect(this.queryLogic.getResultLimit(eq(dnList))).andReturn(maxResults);
// Run the test
PowerMock.replayAll();
RunningQuery subject = new RunningQuery(this.connector, Priority.NORMAL, this.queryLogic, this.query, methodAuths, principal, new QueryMetricFactoryImpl());
ResultsPage result1 = subject.next();
String result2 = subject.toString();
QueryMetric.Lifecycle status = subject.getMetric().getLifecycle();
PowerMock.verifyAll();
// Verify results
assertNotNull("Expected a non-null page", result1);
assertNotNull("Expected a non-null list of results", result1.getResults());
assertEquals("Expected 2 non-null items in the list of results", 2, result1.getResults().size());
assertSame("Expected status to be closed", status, QueryMetric.Lifecycle.RESULTS);
assertNotNull("Expected a non-null toString() representation", result2);
assertSame("Expected lifecycle to be results", QueryMetric.Lifecycle.RESULTS, subject.getMetric().getLifecycle());
}
use of datawave.security.authorization.DatawavePrincipal in project datawave by NationalSecurityAgency.
the class UserOperationsBean method listEffectiveAuthorizations.
/**
* Lists the "effective" Accumulo user authorizations for the calling user. These are authorizations that are returned by the authorization service
* (possibly mapped to different values, or additional values added for Accumulo compatibility) intersected with the authorizations of the user that is used
* to connect to Accumulo. The authorizations returned by the call can be passed to query calls in order to return the maximum amount of data the user is
* authorized to see. Or, authorizations can be removed from this list to downgrade a query.
* <p>
* <strong>WARNING:</strong> If this call is made by a server proxying for a user (and/or other servers) then the response will contain multiple
* authorizations lists--one per entity. It is up to the caller to decide how to combine them if they wish to present a list to the user for downgrading.
* Note that {@link AuthorizationsListBase#getAllAuths()}, due to recent changes, actually returns only the user's authorizations. That is, these are the
* authorizations for the calling or proxied entity that represents a human, otherwise, the calling entity's authorizations. This list is sufficient for use
* in downgrading, but it should be noted the list is not necessarily representative of data that will be returned from a query. When evaluating data for
* return to a called, the data is tested against every authorization set listed here, and it must pass all of them to be returned. Therefore, if the user
* has the authorization FOO, but one of the other proxied entities in the chain does not, no data with FOO will be returned even though
* listEffectiveAuthorizations indicates the user has that authorization.
* <p>
* An example scenario where this comes into play is an external person querying through an internal server. The external party will have an authorization
* for their organization, say EXT1 for example, whereas the server will have the INT authorization. We want to be able to return data with releasabilities
* such as {@code INT&EXT1}, {@code INT&ALL_EXT}, but not data such as {@code INT&EXT2}. There is no single merged list of authorizations that will allow
* the correct data to come back. So, instead we test all data against each authorization set. For the {@code INT&EXT2} data example, the server's
* authorizations will allow the data to be returned since the server has INT. The user's authorizations will not allow the data to be returned however
* since the user has neither INT nor EXT2. In this scenario, the result for {@link AuthorizationsListBase#getAllAuths()} will contain both INT and EXT1
* even though the user does not have INT. The INT auth must be passed when queries are created, else no data would be returned (since the INT auth would be
* removed from the server's auths and then no data would be returned).
* <p>
* For most use cases, a GUI can compute the intersection of all authorizations that are not domains and then include the union of organizations. This will
* not always be the case, however. Consider data marked with something like: {@code FOO&INT|FOO&EXT}. If a system needs to support querying data such as
* that, then a simple intersection of everything except organization will no longer work.
* <p>
* Note that the the return type can be changed by specifying an Accept header, or by adding a suffix to the request URL. The following suffix to return
* type mppings are:
* <ul>
* <li>txt: text/plain
* <li>xml: application/xml
* <li>json: application/json
* </ul>
* For example, the URL
*
* <pre>
* <baseURL>/User/listEffectiveAuthorizations.json
* </pre>
*
* will return the results in JSON format.
*
* @return the user and proxied entities' authorizations
*/
@GET
@Path("/listEffectiveAuthorizations")
@Produces({ "application/xml", "text/xml", "text/plain", "application/json", "text/yaml", "text/x-yaml", "application/x-yaml", "application/x-protobuf", "text/html" })
public AuthorizationsListBase listEffectiveAuthorizations() {
final AuthorizationsListBase list = responseObjectFactory.getAuthorizationsList();
// Find out who/what called this method
Principal p = context.getCallerPrincipal();
String name = p.getName();
if (p instanceof DatawavePrincipal) {
DatawavePrincipal datawavePrincipal = (DatawavePrincipal) p;
name = datawavePrincipal.getShortName();
// Add the user DN's auths into the authorization list
DatawaveUser primaryUser = datawavePrincipal.getPrimaryUser();
list.setUserAuths(primaryUser.getDn().subjectDN(), primaryUser.getDn().issuerDN(), new HashSet<>(primaryUser.getAuths()));
// Now add all entity auth sets into the list
datawavePrincipal.getProxiedUsers().forEach(u -> list.addAuths(u.getDn().subjectDN(), u.getDn().issuerDN(), new HashSet<>(u.getAuths())));
// Add the role to authorization mapping.
// NOTE: Currently this is only added for the primary user, which is really all anyone should care about in terms of mucking with
// authorizations. When used for queries, all non-primary users have all of their auths included -- there is no downgrading.
list.setAuthMapping(datawavePrincipal.getPrimaryUser().getRoleToAuthMapping().asMap());
}
log.trace(name + " has authorizations union " + list.getAllAuths());
return list;
}
Aggregations