public static function refuseAuthenticatedUsers($responseType = 'redirect') { self::validateResponseType($responseType); return function () use($responseType) { if (!Auth::loggedIn()) { return true; } $errorMessage = 'You must be logged out to perform that action.'; \Directus\Slim\Middleware::refuseWithErrorMessage($errorMessage, $responseType); }; }
public function save() { $this->initialize(); $currentUserId = null; if (Auth::loggedIn()) { $currentUser = Auth::getUserInfo(); $currentUserId = intval($currentUser['id']); } /** * ACL Enforcement * Note: Field Write Blacklists are enforced at the object setter level * (AARG#__set, AARG#populate, AARG#offsetSet) */ if (!$this->rowExistsInDatabase()) { /** * Enforce Privilege: Table Add */ if (!$this->acl->hasTablePrivilege($this->table, 'add')) { $aclErrorPrefix = $this->acl->getErrorMessagePrefix(); throw new UnauthorizedTableAddException($aclErrorPrefix . 'Table add access forbidden on table ' . $this->table); } } else { $cmsOwnerId = $this->acl->getRecordCmsOwnerId($this, $this->table); /** * Enforce Privilege: "Little" Edit (I am the record CMS owner) */ if ($cmsOwnerId === intval($currentUserId)) { if (!$this->acl->hasTablePrivilege($this->table, 'edit')) { $recordPk = self::stringifyPrimaryKeyForRecordDebugRepresentation($this->primaryKeyData); $aclErrorPrefix = $this->acl->getErrorMessagePrefix(); throw new UnauthorizedTableEditException($aclErrorPrefix . 'Table edit access forbidden on `' . $this->table . '` table record with ' . $recordPk . ' owned by the authenticated CMS user (#' . $cmsOwnerId . ').'); } } else { if (!$this->acl->hasTablePrivilege($this->table, 'bigedit')) { $recordPk = self::stringifyPrimaryKeyForRecordDebugRepresentation($this->primaryKeyData); $recordOwner = false === $cmsOwnerId ? 'no magic owner column' : 'the CMS owner #' . $cmsOwnerId; $aclErrorPrefix = $this->acl->getErrorMessagePrefix(); throw new UnauthorizedTableBigEditException($aclErrorPrefix . 'Table bigedit access forbidden on `' . $this->table . '` table record with ' . $recordPk . ' and ' . $recordOwner . '.'); } } } try { return parent::save(); } catch (InvalidQueryException $e) { $this->logger()->fatal('Error running save on this data: ' . print_r($this->data, true)); throw $e; } }
public function preSaveDataHook(array $rowData, $rowExistsInDatabase = false) { $log = Bootstrap::get('log'); if (isset($rowData['id'])) { $logger = Bootstrap::get('log'); $TableGateway = new AclAwareTableGateway($this->acl, $this->table, $this->sql->getAdapter()); $dbRecord = $TableGateway->find($rowData['id']); if (false === $dbRecord) { // @todo is it better to throw an exception here? $rowExistsInDatabase = false; } } // User is updating themselves. // Corresponds to a ping indicating their last activity. // Updated their "last_access" value. if (AuthProvider::loggedIn()) { $currentUser = AuthProvider::getUserInfo(); if (isset($rowData['id']) && $rowData['id'] == $currentUser['id']) { $rowData['last_access'] = new Expression("NOW()"); } } return $rowData; }
/** * @param Delete $delete * @return mixed * @throws Exception\RuntimeException * @throws \Directus\Acl\Exception\UnauthorizedTableBigDeleteException * @throws \Directus\Acl\Exception\UnauthorizedTableDeleteException */ protected function executeDelete(Delete $delete) { $cuurrentUserId = null; if (Auth::loggedIn()) { $currentUser = Auth::getUserInfo(); $currentUserId = intval($currentUser['id']); } $deleteState = $delete->getRawState(); $deleteTable = $this->getRawTableNameFromQueryStateTable($deleteState['table']); $cmsOwnerColumn = $this->acl->getCmsOwnerColumnByTable($deleteTable); $canBigHardDelete = $this->acl->hasTablePrivilege($deleteTable, 'bigharddelete'); $canHardDelete = $this->acl->hasTablePrivilege($deleteTable, 'harddelete'); $aclErrorPrefix = $this->acl->getErrorMessagePrefix(); // Is this table a junction table? $deleteTableSchema = TableSchema::getTable($deleteTable); $isDeleteTableAJunction = array_key_exists('is_junction_table', $deleteTableSchema) ? (bool) $deleteTableSchema['is_junction_table'] : false; if ($isDeleteTableAJunction || !TableSchema::hasTableColumn($deleteTable, STATUS_COLUMN_NAME)) { if ($this->acl->hasTablePrivilege($deleteTable, 'bigdelete')) { $canBigHardDelete = true; } else { if ($this->acl->hasTablePrivilege($deleteTable, 'delete')) { $canHardDelete = true; } } } // @todo: clean way if ($deleteTable === 'directus_bookmarks') { $canBigHardDelete = true; } /** * ACL Enforcement */ if (!$canBigHardDelete && !$canHardDelete) { throw new UnauthorizedTableBigDeleteException($aclErrorPrefix . "BigHardDelete/HardDelete access forbidden on table `{$deleteTable}`."); } if (false === $cmsOwnerColumn) { // cannot delete if there's no magic owner column and can't big delete if (!$canBigHardDelete) { // All deletes are "big" deletes if there is no magic owner column. throw new UnauthorizedTableBigDeleteException($aclErrorPrefix . "The table `{$deleteTable}` is missing the `user_create_column` within `directus_tables` (BigHardDelete Permission Forbidden)"); } } else { if (!$canBigHardDelete) { // Who are the owners of these rows? list($predicateResultQty, $predicateOwnerIds) = $this->acl->getCmsOwnerIdsByTableGatewayAndPredicate($this, $deleteState['where']); if (in_array($currentUserId, $predicateOwnerIds)) { $exceptionMessage = "Table harddelete access forbidden on {$predicateResultQty} `{$deleteTable}` table records owned by the authenticated CMS user (#{$currentUserId})."; $aclErrorPrefix = $this->acl->getErrorMessagePrefix(); throw new UnauthorizedTableDeleteException($aclErrorPrefix . $exceptionMessage); } } } try { return parent::executeDelete($delete); } catch (\Zend\Db\Adapter\Exception\InvalidQueryException $e) { if ('production' !== DIRECTUS_ENV) { throw new \RuntimeException("This query failed: " . $this->dumpSql($delete), 0, $e); } // @todo send developer warning throw $e; } }
$response['message'] = 'You do not have access to this system'; return JsonView::render($response); } if ($response['success']) { unset($response['message']); $response['last_page'] = json_decode($user['last_page']); $set = array('last_login' => new Expression('NOW()')); $where = array('id' => $user['id']); $updateResult = $Users->update($set, $where); $Activity = new DirectusActivityTableGateway($acl, $ZendDb); $Activity->recordLogin($user['id']); } JsonView::render($response); })->name('auth_login'); $app->get("/{$v}/auth/logout(/:inactive)", function ($inactive = null) use($app) { if (Auth::loggedIn()) { Auth::logout(); } if ($inactive) { $app->redirect(DIRECTUS_PATH . "login.php?inactive=1"); } else { $app->redirect(DIRECTUS_PATH . "login.php"); } })->name('auth_logout'); $app->get("/{$v}/auth/nonces/?", function () use($app, $requestNonceProvider) { $all_nonces = $requestNonceProvider->getAllNonces(); $response = array('nonces' => $all_nonces); JsonView::render($response); })->name('auth_nonces'); // debug helper $app->get("/{$v}/auth/session/?", function () use($app) {
/** * Construct Acl provider * @return \Directus\Acl */ private static function acl() { $acl = new acl(); $db = self::get('ZendDb'); $DirectusTablesTableGateway = new DirectusTablesTableGateway($acl, $db); $getTables = function () use($DirectusTablesTableGateway) { return $DirectusTablesTableGateway->select()->toArray(); }; $tableRecords = $DirectusTablesTableGateway->memcache->getOrCache(MemcacheProvider::getKeyDirectusTables(), $getTables, 1800); $magicOwnerColumnsByTable = []; foreach ($tableRecords as $tableRecord) { if (!empty($tableRecord['user_create_column'])) { $magicOwnerColumnsByTable[$tableRecord['table_name']] = $tableRecord['user_create_column']; } } $acl::$cms_owner_columns_by_table = $magicOwnerColumnsByTable; if (AuthProvider::loggedIn()) { $currentUser = AuthProvider::getUserInfo(); $Users = new DirectusUsersTableGateway($acl, $db); $cacheFn = function () use($currentUser, $Users) { return $Users->find($currentUser['id']); }; $cacheKey = MemcacheProvider::getKeyDirectusUserFind($currentUser['id']); $currentUser = $Users->memcache->getOrCache($cacheKey, $cacheFn, 10800); if ($currentUser) { $privilegesTable = new DirectusPrivilegesTableGateway($acl, $db); $acl->setGroupPrivileges($privilegesTable->getGroupPrivileges($currentUser['group'])); } } return $acl; }
<?php //If config file doesnt exist, go to install file if (!file_exists('api/config.php') || filesize('api/config.php') == 0) { header('Location: installation/index.php'); } // Composer Autoloader $loader = (require 'api/vendor/autoload.php'); $loader->add("Directus", dirname(__FILE__) . "/api/core/"); require "api/config.php"; require "api/globals.php"; /** * Temporary solution for disabling this page for logged in users. */ if (\Directus\Auth\Provider::loggedIn()) { header('Location: ' . DIRECTUS_PATH); exit; } // Get current commit hash $git = __DIR__ . '/.git'; $cacheBuster = Directus\Util\Git::getCloneHash($git); ?> <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no,maximum-scale=1.0"> <title>Directus Login</title> <!-- Icons -->
if (!AuthProvider::loggedIn()) { $request_uri = $_SERVER['REQUEST_URI']; if (strpos($request_uri, DIRECTUS_PATH) === 0) { $request_uri = substr($request_uri, strlen(DIRECTUS_PATH)); } $redirect = htmlspecialchars(trim($request_uri, '/'), ENT_QUOTES, 'UTF-8'); if ($redirect) { $_SESSION['_directus_login_redirect'] = $redirect; $redirect = '?redirect=' . $redirect; } header('Location: ' . DIRECTUS_PATH . 'login.php' . $redirect); die; } $acl = Bootstrap::get('acl'); $ZendDb = Bootstrap::get('ZendDb'); $authenticatedUser = AuthProvider::loggedIn() ? AuthProvider::getUserInfo() : array(); function getNonces() { $requestNonceProvider = new RequestNonceProvider(); $nonces = array_merge($requestNonceProvider->getOptions(), array('pool' => $requestNonceProvider->getAllNonces())); return $nonces; } function getStorageAdapters() { $config = Bootstrap::get('config'); $storageAdapter = $config['filesystem']; return [$storageAdapter['adapter'] => ['adapter' => $storageAdapter['adapter'], 'root_url' => $storageAdapter['root_url'], 'root_thumb_url' => $storageAdapter['root_thumb_url']]]; } function parseTables($tableSchema) { $tables = array();
$DirectusUsersTableGateway = new DirectusUsersTableGateway($acl, $ZendDb); Auth::setUserCacheRefreshProvider(function ($userId) use($DirectusUsersTableGateway) { $cacheFn = function () use($userId, $DirectusUsersTableGateway) { return $DirectusUsersTableGateway->find($userId); }; $cacheKey = MemcacheProvider::getKeyDirectusUserFind($userId); $user = $DirectusUsersTableGateway->memcache->getOrCache($cacheKey, $cacheFn, 10800); return $user; }); if (Auth::loggedIn()) { $user = Auth::getUserRecord(); $acl->setUserId($user['id']); $acl->setGroupId($user['group']); } $app->hook('slim.before.dispatch', function () use($app) { if (!Auth::loggedIn()) { http_response_code(403); echo "<h1>403 Forbidden</h1>"; // $app->halt(403); // Never works very well exit; } }); $app->get("/:id/:format(/:filename)", function ($id, $format, $filename) use($app, $acl, $ZendDb) { $notFound = function () { http_response_code(404); echo "<h1>404 Not found</h1>"; exit; }; $DirectusMedia = new TableGateway('directus_files', $ZendDb); $media = $DirectusMedia->select(function ($select) use($id) { $select->where->equalTo('id', $id);
/** * @param Delete $delete * @return mixed * @throws Exception\RuntimeException * @throws \Directus\Acl\Exception\UnauthorizedTableBigDeleteException * @throws \Directus\Acl\Exception\UnauthorizedTableDeleteException */ protected function executeDelete(Delete $delete) { $cuurrentUserId = null; if (Auth::loggedIn()) { $currentUser = Auth::getUserInfo(); $currentUserId = intval($currentUser['id']); } $deleteState = $delete->getRawState(); $deleteTable = $this->getRawTableNameFromQueryStateTable($deleteState['table']); $cmsOwnerColumn = $this->acl->getCmsOwnerColumnByTable($deleteTable); $canBigDelete = $this->acl->hasTablePrivilege($deleteTable, 'bigdelete'); $canDelete = $this->acl->hasTablePrivilege($deleteTable, 'delete'); $aclErrorPrefix = $this->acl->getErrorMessagePrefix(); if (!TableSchema::hasTableColumn($deleteTable, STATUS_COLUMN_NAME)) { if ($this->acl->hasTablePrivilege($deleteTable, 'bigdelete')) { $canBigDelete = true; } else { if ($this->acl->hasTablePrivilege($deleteTable, 'delete')) { $canDelete = true; } } } // @todo: clean way if ($deleteTable === 'directus_bookmarks') { $canBigDelete = true; } /** * ACL Enforcement */ if (!$canBigDelete && !$canDelete) { throw new UnauthorizedTableBigDeleteException($aclErrorPrefix . ' forbidden to hard delete on table `' . $deleteTable . '` because it has Status Column.'); } if (false === $cmsOwnerColumn) { // cannot delete if there's no magic owner column and can't big delete if (!$canBigDelete) { // All deletes are "big" deletes if there is no magic owner column. throw new UnauthorizedTableBigDeleteException($aclErrorPrefix . 'The table `' . $deleteTable . '` is missing the `user_create_column` within `directus_tables` (BigHardDelete Permission Forbidden)'); } } else { if (!$canBigDelete) { // Who are the owners of these rows? list($predicateResultQty, $predicateOwnerIds) = $this->acl->getCmsOwnerIdsByTableGatewayAndPredicate($this, $deleteState['where']); if (!in_array($currentUserId, $predicateOwnerIds)) { // $exceptionMessage = "Table harddelete access forbidden on $predicateResultQty `$deleteTable` table records owned by the authenticated CMS user (#$currentUserId)."; $groupsTableGateway = self::makeTableGatewayFromTableName($this->acl, 'directus_groups', $this->adapter); $group = $groupsTableGateway->find($this->acl->getGroupId()); $exceptionMessage = '[' . $group['name'] . '] permissions only allow you to [delete] your own items.'; // $aclErrorPrefix = $this->acl->getErrorMessagePrefix(); throw new UnauthorizedTableDeleteException($exceptionMessage); } } } try { $this->emitter->run('table.delete:before', [$deleteTable]); $this->emitter->run('table.delete.' . $deleteTable . ':before'); $result = parent::executeDelete($delete); $this->emitter->run('table.delete', [$deleteTable]); $this->emitter->run('table.delete:after', [$deleteTable]); $this->emitter->run('table.delete.' . $deleteTable); $this->emitter->run('table.delete.' . $deleteTable . ':after'); return $result; } catch (\Zend\Db\Adapter\Exception\InvalidQueryException $e) { if ('production' !== DIRECTUS_ENV) { throw new \RuntimeException('This query failed: ' . $this->dumpSql($delete), 0, $e); } // @todo send developer warning throw $e; } }