*/
private $explicitJoins = [];
+ /**
+ * @var array
+ */
+ private $entityAccess = [];
+
/**
* @param \Civi\Api4\Generic\DAOGetAction $apiGet
*/
$tableName = CoreUtil::getTableName($this->getEntity());
$this->query = \CRM_Utils_SQL_Select::from($tableName . ' ' . self::MAIN_TABLE_ALIAS);
+ $this->entityAccess[$this->getEntity()] = TRUE;
+
// Add ACLs first to avoid redundant subclauses
$baoName = CoreUtil::getBAOFromApiName($this->getEntity());
$this->query->where($this->getAclClause(self::MAIN_TABLE_ALIAS, $baoName));
return $field;
}
+ /**
+ * Check the "gatekeeper" permissions for performing "get" on a given entity.
+ *
+ * @param $entity
+ * @return bool
+ */
+ public function checkEntityAccess($entity) {
+ if (!$this->getCheckPermissions()) {
+ return TRUE;
+ }
+ if (!isset($this->entityAccess[$entity])) {
+ $this->entityAccess[$entity] = (bool) civicrm_api4($entity, 'getActions', [
+ 'where' => [['name', '=', 'get']],
+ 'select' => ['name'],
+ ])->first();
+ }
+ return $this->entityAccess[$entity];
+ }
+
/**
* Join onto other entities as specified by the api call.
*
$entity = array_shift($join);
// Which might contain an alias. Split on the keyword "AS"
list($entity, $alias) = array_pad(explode(' AS ', $entity), 2, NULL);
+ // Ensure permissions
+ if (!$this->checkEntityAccess($entity)) {
+ continue;
+ }
// Ensure alias is a safe string, and supply default if not given
$alias = $alias ? \CRM_Utils_String::munge($alias, '_', 256) : strtolower($entity);
// First item in the array is a boolean indicating if the join is required (aka INNER or LEFT).
namespace Civi\Api4\Service\Schema;
+use Civi\API\Exception\UnauthorizedException;
use Civi\Api4\Query\Api4SelectQuery;
+use Civi\Api4\Utils\CoreUtil;
class Joiner {
/**
foreach ($fullPath as $link) {
$target = $link->getTargetTable();
$alias = $link->getAlias();
- $bao = \CRM_Core_DAO_AllCoreTables::getBAOClassName(\CRM_Core_DAO_AllCoreTables::getClassForTable($target));
+ $joinEntity = CoreUtil::getApiNameFromTableName($target);
+
+ if ($joinEntity && !$query->checkEntityAccess($joinEntity)) {
+ throw new UnauthorizedException('Cannot join to ' . $joinEntity);
+ }
+
+ $bao = $joinEntity ? CoreUtil::getBAOFromApiName($joinEntity) : NULL;
$conditions = $link->getConditionsForJoin($baseTableAlias);
- // Custom fields do not have a bao, and currently do not have field-specific ACLs
if ($bao) {
$conditions = array_merge($conditions, $query->getAclClause($alias, $bao, $joinPath));
}