From 95895ed326dc859a685aae06179f22937b8cc9d4 Mon Sep 17 00:00:00 2001 From: Rahul Patel Date: Fri, 10 May 2019 01:30:43 +0530 Subject: [PATCH] #717 --- .../TableGateway/RelationalTableGateway.php | 26 ++- src/core/Directus/Permissions/Acl.php | 50 +++++- tests/api/AuthTest.php | 55 ------ tests/api/CollectionTest.php | 156 ------------------ 4 files changed, 65 insertions(+), 222 deletions(-) delete mode 100644 tests/api/AuthTest.php delete mode 100644 tests/api/CollectionTest.php diff --git a/src/core/Directus/Database/TableGateway/RelationalTableGateway.php b/src/core/Directus/Database/TableGateway/RelationalTableGateway.php index a177336285..9ecd5d7836 100644 --- a/src/core/Directus/Database/TableGateway/RelationalTableGateway.php +++ b/src/core/Directus/Database/TableGateway/RelationalTableGateway.php @@ -1469,9 +1469,21 @@ protected function shouldIgnoreQueryFilter($operator, $value) */ protected function processFilter(Builder $query, array $filters = []) { - $filters = $this->parseDotFilters($query, $filters); - - foreach ($filters as $column => $conditions) { + //Logic for blacklisted fields + $blackListStatuses = []; + foreach($filters as $column => $conditions){ + $column = explode('.', $column); + $column = array_shift($column); + $fieldReadBlackListDetails = $this->acl->getStatusesOnReadFieldBlacklist($this->getTable(),$column); + if (isset($fieldReadBlackListDetails['isReadBlackList']) && $fieldReadBlackListDetails['isReadBlackList']) { + throw new Exception\ForbiddenFieldAccessException($column); + }else if(isset($fieldReadBlackListDetails['statuses']) && !empty ($fieldReadBlackListDetails['statuses'])){ + $blackListStatuses = array_merge($blackListStatuses,array_values($fieldReadBlackListDetails['statuses'])); + } + } + $filters = $this->parseDotFilters($query, $filters); + + foreach ($filters as $column => $conditions) { if ($conditions instanceof Filter) { $column = $conditions->getIdentifier(); $conditions = $conditions->getValue(); @@ -1485,6 +1497,14 @@ protected function processFilter(Builder $query, array $filters = []) $this->doFilter($query, $column, $condition, $this->getTable()); } } + //Condition for blacklisted statuses + if(!empty($blackListStatuses)){ + $statusCondition = [ + 'nin' => array_unique($blackListStatuses) + ]; + $statusFieldName = SchemaService::getStatusFieldName($this->getTable()); + $this->doFilter($query, $statusFieldName, $statusCondition, $this->getTable()); + } } /** diff --git a/src/core/Directus/Permissions/Acl.php b/src/core/Directus/Permissions/Acl.php index 5adaa195e4..7e7b54d051 100644 --- a/src/core/Directus/Permissions/Acl.php +++ b/src/core/Directus/Permissions/Acl.php @@ -1252,15 +1252,16 @@ public function allowTo($action, $level, $collection, $status = null) $statuses = $this->getCollectionStatuses($collection); $allowed = false; - foreach ($statuses as $status) { - $permission = $this->getPermission($collection, $status); - $permissionLevel = ArrayUtils::get($permission, $action); - if ($this->can($permissionLevel, $level)) { - $allowed = true; - break; + if($statuses){ + foreach ($statuses as $status) { + $permission = $this->getPermission($collection, $status); + $permissionLevel = ArrayUtils::get($permission, $action); + if ($this->can($permissionLevel, $level)) { + $allowed = true; + break; + } } } - return $allowed; } else { $permissionLevel = ArrayUtils::get($permission, $action); @@ -1293,7 +1294,40 @@ public function allowToOnce($action, $collection) return $allowed; } - + + /** + * Gets the statuses on which field has been blacklisted + * + * @param string $collection + * @param mixed $status + * + * @return array + */ + public function getStatusesOnReadFieldBlacklist($collection, $field) + { + $blackListStatuses = []; + $collectionPermission = $this->getCollectionPermissions($collection); + $statuses = $this->getCollectionStatuses($collection); + if($statuses){ + foreach($statuses as $status){ + $readFieldBlackList = isset($collectionPermission[$status]['read_field_blacklist']) ? $collectionPermission[$status]['read_field_blacklist'] : []; + if($readFieldBlackList && in_array($field, $readFieldBlackList)){ + $blackListStatuses['statuses'][] = $status; + } + } + //Set flag for field which is blacklist for all statuses + if(isset($blackListStatuses['statuses']) && count($blackListStatuses['statuses']) == count($statuses)){ + $blackListStatuses['isReadBlackList'] = true; + } + }else{ + $readFieldBlackList = isset($collectionPermission['read_field_blacklist']) ? $collectionPermission['read_field_blacklist'] : []; + if($readFieldBlackList && in_array($field, $readFieldBlackList)){ + $blackListStatuses['isReadBlackList'] = true; + } + } + return $blackListStatuses; + } + /** * Returns a list of status the given collection has permission to read * diff --git a/tests/api/AuthTest.php b/tests/api/AuthTest.php deleted file mode 100644 index 9e590b6a23..0000000000 --- a/tests/api/AuthTest.php +++ /dev/null @@ -1,55 +0,0 @@ -http = new GuzzleHttp\Client([ - 'base_uri' => 'http://localhost/directus-api/public/_/', - 'exceptions' => false - ]); - } - - public function tearDown() { - $this->http = null; - } - - public function testAuthentication() - { - - $data = [ - 'form_params' => [ - 'email' => "admin@example.com", - 'password' => "password" - ] - ]; - - $response = $this->http->request('POST', 'auth/authenticate', $data); - - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode($response->getBody(true), true); - $this->assertArrayHasKey('token', $data['data']); - $this->assertTrue(!empty($data['data']['token'])); - - } - - public function testForgotPassword() - { - - $data = [ - 'form_params' => [ - 'email' => "admin@example.com" - ] - ]; - - $response = $this->http->request('POST', 'auth/password/request', $data); - - $this->assertEquals(200, $response->getStatusCode()); - $data = json_decode($response->getBody(true), true); - $this->assertTrue($data['public']); - - } -} \ No newline at end of file diff --git a/tests/api/CollectionTest.php b/tests/api/CollectionTest.php deleted file mode 100644 index c97cf7f681..0000000000 --- a/tests/api/CollectionTest.php +++ /dev/null @@ -1,156 +0,0 @@ -http = new GuzzleHttp\Client([ - 'base_uri' => 'http://localhost/directus-api/public/_/', - 'exceptions' => false - ]); - - //Get token - $data = [ - 'form_params' => [ - 'email' => "admin@example.com", - 'password' => "password" - ] - ]; - - $response = $this->http->request('POST', 'auth/authenticate', $data); - $data = json_decode($response->getBody(true), true); - $this->token = $data['data']['token']; - - } - - public function tearDown() { - $this->http = null; - } - - public function testCreateCollection() - { - $data = [ - 'headers' => ['Authorization' => 'bearer '.$this->token], - 'form_params' => json_decode('{ - "collection": "test111_collection", - "hidden": 0, - "fields": [{ - "type": "integer", - "datatype": "INT", - "length": 15, - "field": "id", - "interface": "primary-key", - "auto_increment": true, - "primary_key": true, - "hidden_detail": true, - "hidden_browse": true - }, { - "type": "status", - "datatype": "VARCHAR", - "length": 20, - "field": "status", - "interface": "status", - "options": { - "status_mapping": { - "published": { - "name": "Published", - "text_color": "white", - "background_color": "accent", - "browse_subdued": false, - "browse_badge": true, - "soft_delete": false, - "published": true - }, - "draft": { - "name": "Draft", - "text_color": "white", - "background_color": "blue-grey-200", - "browse_subdued": true, - "browse_badge": true, - "soft_delete": false, - "published": false - }, - "deleted": { - "name": "Deleted", - "text_color": "white", - "background_color": "red", - "browse_subdued": true, - "browse_badge": true, - "soft_delete": true, - "published": false - } - } - } - }, { - "type": "sort", - "datatype": "INT", - "field": "sort", - "interface": "sort" - }, { - "type": "user_created", - "datatype": "INT", - "field": "created_by", - "interface": "user-created", - "options": { - "template": "{{first_name}} {{last_name}}", - "display": "both" - }, - "readonly": true, - "hidden_detail": true, - "hidden_browse": true - }, { - "type": "datetime_created", - "datatype": "DATETIME", - "field": "created_on", - "interface": "datetime-created", - "readonly": true, - "hidden_detail": true, - "hidden_browse": true - }, { - "type": "user_updated", - "datatype": "INT", - "field": "modified_by", - "interface": "user-updated", - "options": { - "template": "{{first_name}} {{last_name}}", - "display": "both" - }, - "readonly": true, - "hidden_detail": true, - "hidden_browse": true - }, { - "type": "datetime_updated", - "datatype": "DATETIME", - "field": "modified_on", - "interface": "datetime-updated", - "readonly": true, - "hidden_detail": true, - "hidden_browse": true - }] - }',true) - ]; - - //echo "
";
-        //print_r($data);exit;
-        $response = $this->http->request('POST', 'collections', $data);
-        $this->assertEquals(200, $response->getStatusCode());
-        $data = json_decode($response->getBody(true), true);
-        $this->assertArrayHasKey('collection', $data['data']);
-        $this->assertTrue(!empty($data['data']['collection']));
-    }
-    
-    public function testDeleteCollection()
-    {
-        $data = [
-            'headers' => ['Authorization' => 'bearer '.$this->token],
-        ];
-        
-        $response = $this->http->request('DELETE', 'collections/test111_collection', $data);
-        
-        $this->assertEquals(204, $response->getStatusCode());        
-    }
-    
-}
\ No newline at end of file