}
}
private void internalPreRead(final ObserverContext<RegionCoprocessorEnvironment> c,
final Query query, OpType opType) throws IOException {
Filter filter = query.getFilter();
// Don't wrap an AccessControlFilter
if (filter != null && filter instanceof AccessControlFilter) {
return;
}
User user = getActiveUser();
RegionCoprocessorEnvironment env = c.getEnvironment();
Map<byte[],? extends Collection<byte[]>> families = null;
switch (opType) {
case GET:
case EXISTS:
families = ((Get)query).getFamilyMap();
break;
case SCAN:
families = ((Scan)query).getFamilyMap();
break;
default:
throw new RuntimeException("Unhandled operation " + opType);
}
AuthResult authResult = permissionGranted(opType, user, env, families, Action.READ);
HRegion region = getRegion(env);
TableName table = getTableName(region);
Map<ByteRange, Integer> cfVsMaxVersions = Maps.newHashMap();
for (HColumnDescriptor hcd : region.getTableDesc().getFamilies()) {
cfVsMaxVersions.put(new SimpleByteRange(hcd.getName()), hcd.getMaxVersions());
}
if (!authResult.isAllowed()) {
if (!cellFeaturesEnabled || compatibleEarlyTermination) {
// Old behavior: Scan with only qualifier checks if we have partial
// permission. Backwards compatible behavior is to throw an
// AccessDeniedException immediately if there are no grants for table
// or CF or CF+qual. Only proceed with an injected filter if there are
// grants for qualifiers. Otherwise we will fall through below and log
// the result and throw an ADE. We may end up checking qualifier
// grants three times (permissionGranted above, here, and in the
// filter) but that's the price of backwards compatibility.
if (hasFamilyQualifierPermission(user, Action.READ, env, families)) {
Filter ourFilter = new AccessControlFilter(authManager, user, table,
query.getACLStrategy() ? AccessControlFilter.Strategy.CHECK_CELL_FIRST :
AccessControlFilter.Strategy.CHECK_TABLE_AND_CF_ONLY,
cfVsMaxVersions);
// wrap any existing filter
if (filter != null) {
ourFilter = new FilterList(FilterList.Operator.MUST_PASS_ALL,
Lists.newArrayList(ourFilter, filter));
}
authResult.setAllowed(true);;
authResult.setReason("Access allowed with filter");
switch (opType) {
case GET:
case EXISTS:
((Get)query).setFilter(ourFilter);
break;
case SCAN:
((Scan)query).setFilter(ourFilter);
break;
default:
throw new RuntimeException("Unhandled operation " + opType);
}
}
} else {
// New behavior: Any access we might be granted is more fine-grained
// than whole table or CF. Simply inject a filter and return what is
// allowed. We will not throw an AccessDeniedException. This is a
// behavioral change since 0.96.
Filter ourFilter = new AccessControlFilter(authManager, user, table,
query.getACLStrategy() ? AccessControlFilter.Strategy.CHECK_CELL_FIRST :
AccessControlFilter.Strategy.CHECK_CELL_DEFAULT,
cfVsMaxVersions);
// wrap any existing filter
if (filter != null) {