TYPO3  7.6
DatabaseUserPermissionCheck.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Backend\Form\FormDataProvider;
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
22 use TYPO3\CMS\Backend\Form\Exception\AccessDeniedException;
23 use TYPO3\CMS\Backend\Form\Exception\AccessDeniedTableModifyException;
24 use TYPO3\CMS\Backend\Form\Exception\AccessDeniedPageEditException;
25 use TYPO3\CMS\Backend\Form\Exception\AccessDeniedPageNewException;
26 use TYPO3\CMS\Backend\Form\Exception\AccessDeniedContentEditException;
27 use TYPO3\CMS\Backend\Form\Exception\AccessDeniedRootNodeException;
28 use TYPO3\CMS\Backend\Form\Exception\AccessDeniedEditInternalsException;
29 use TYPO3\CMS\Backend\Form\Exception\AccessDeniedHookException;
30 
35 {
52  public function addData(array $result)
53  {
54  $backendUser = $this->getBackendUser();
55 
56  // Early return for admins
57  if ($backendUser->isAdmin()) {
58  $result['userPermissionOnPage'] = Permission::ALL;
59  return $result;
60  }
61 
62  if (!$backendUser->check('tables_modify', $result['tableName'])) {
63  // If user has no modify rights on table, processing is stopped by throwing an
64  // exception immediately. This case can not be circumvented by hooks.
66  'No table modify permission for user ' . $backendUser->user['uid'] . ' on table ' . $result['tableName'],
67  1437683248
68  );
69  }
70 
71  $exception = null;
72  $userHasAccess = false;
73  $userPermissionOnPage = Permission::NOTHING;
74  if ($result['command'] === 'new') {
75  // A new record is created. Access rights of parent record are important here
76  // @todo: In case of new inline child, parentPageRow should probably be the
77  // @todo: "inlineFirstPid" page - Maybe effectivePid and parentPageRow should be calculated differently then?
78  if (is_array($result['parentPageRow'])) {
79  // Record is added below an existing page
80  $userPermissionOnPage = $backendUser->calcPerms($result['parentPageRow']);
81  if ($result['tableName'] === 'pages') {
82  // New page is created, user needs PAGE_NEW for this
83  if ((bool)($userPermissionOnPage & Permission::PAGE_NEW)) {
84  $userHasAccess = true;
85  } else {
86  $exception = new AccessDeniedPageNewException(
87  'No page new permission for user ' . $backendUser->user['uid'] . ' on page ' . $result['databaseRow']['uid'],
88  1437745640
89  );
90  }
91  } else {
92  // A regular record is added, not a page. User needs CONTENT_EDIT permission
93  if ((bool)($userPermissionOnPage & Permission::CONTENT_EDIT)) {
94  $userHasAccess = true;
95  } else {
96  $exception = new AccessDeniedContentEditException(
97  'No content new permission for user ' . $backendUser->user['uid'] . ' on page ' . $result['parentPageRow']['uid'],
98  1437745759
99  );
100  }
101  }
102  } else {
103  // Record is added to root node. This was not defined and implicitly *allowed*
104  // with previous access check implementation. It is currently unsure when exactly
105  // this can be triggered, so we'll throw a RuntimeException hinting us about this.
106  throw new \RuntimeException(
107  'Not implemented. User ' . $backendUser->user['uid'] . ' creats new record ' . $result['tableName'] . ' on root node.',
108  1437745221
109  );
110  }
111  } else {
112  // A page or a record on a page is edited
113  if ($result['tableName'] === 'pages') {
114  // A page record is edited, check edit rights of this record directly
115  $userPermissionOnPage = $backendUser->calcPerms($result['databaseRow']);
116  if ((bool)($userPermissionOnPage & Permission::PAGE_EDIT)) {
117  $userHasAccess = true;
118  } else {
119  $exception = new AccessDeniedPageEditException(
120  'No page edit permission for user ' . $backendUser->user['uid'] . ' on page ' . $result['databaseRow']['uid'],
121  1437679336
122  );
123  }
124  } else {
125  // A non page record is edited.
126  if (is_array($result['parentPageRow'])) {
127  // If there is a parent page row, check content edit right of user
128  $userPermissionOnPage = $backendUser->calcPerms($result['parentPageRow']);
129  if ((bool)($userPermissionOnPage & Permission::CONTENT_EDIT)) {
130  $userHasAccess = true;
131  } else {
132  $exception = new AccessDeniedContentEditException(
133  'No content edit permission for user ' . $backendUser->user['uid'] . ' on page ' . $result['parentPageRow']['uid'],
134  1437679657
135  );
136  }
137  } elseif (BackendUtility::isRootLevelRestrictionIgnored($result['tableName'])) {
138  // Non admin is editing a record on root node for a table that is actively allowed
139  $userHasAccess = true;
140  $userPermissionOnPage = Permission::ALL;
141  } else {
142  // Non admin has no edit permission on root node records
143  // @todo: This probably needs further handling, see http://review.typo3.org/40835
144  $exception = new AccessDeniedRootNodeException(
145  'No content edit permission for user ' . $backendUser->user['uid'] . ' on page root node',
146  1437679856
147  );
148  }
149  }
150  if ($userHasAccess) {
151  // If general access is allowed, check "recordEditAccessInternals"
152  $userHasAccess = $backendUser->recordEditAccessInternals($result['tableName'], $result['databaseRow']);
153  if (!$userHasAccess) {
154  $exception = new AccessDeniedEditInternalsException(
155  $backendUser->errorMsg,
156  1437687404
157  );
158  }
159  }
160  }
161 
162  if ($userHasAccess && $exception) {
163  // Having user access TRUE here and an exception defined must not happen,
164  // indicates an internal error and throws a logic exception
165  throw new \LogicException(
166  'Access was TRUE but an exception was raised as well for table ' . $result['tableName'] . ' and user ' . $backendUser->user['uid'],
167  1437688402
168  );
169  }
170 
171  if (!empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/alt_doc.php']['makeEditForm_accessCheck'])
172  && is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/alt_doc.php']['makeEditForm_accessCheck'])
173  ) {
174  // A hook may modify the $userHasAccess decision. Previous state is saved to see if a hook changed
175  // a previous decision from TRUE to FALSE to throw a specific exception in this case
176  $userHasAccessBeforeHook = $userHasAccess;
177  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/alt_doc.php']['makeEditForm_accessCheck'] as $methodReference) {
178  $parameters = array(
179  'table' => $result['tableName'],
180  'uid' => $result['databaseRow']['uid'],
181  'cmd' => $result['command'],
182  'hasAccess' => $userHasAccess,
183  );
184  $userHasAccess = (bool)GeneralUtility::callUserFunction($methodReference, $parameters, $this);
185  }
186  if ($userHasAccessBeforeHook && !$userHasAccess) {
187  $exception = new AccessDeniedHookException(
188  'Access to table ' . $result['tableName'] . ' for user ' . $backendUser->user['uid'] . ' was denied by a makeEditForm_accessCheck hook',
189  1437689705
190  );
191  }
192  if (!$userHasAccessBeforeHook && $userHasAccess) {
193  // Unset a previous exception if hook allowed access where previous checks didn't
194  $exception = null;
195  }
196  }
197 
198  if (!$userHasAccess && !$exception) {
199  // User has no access, but no according exception was defined. This is an
200  // internal error and throws a logic exception.
201  throw new \LogicException(
202  'Access to table ' . $result['tableName'] . ' denied, but no reason given',
203  1437690507
204  );
205  }
206 
207  if ($exception) {
208  throw $exception;
209  }
210 
211  $result['userPermissionOnPage'] = $userPermissionOnPage;
212 
213  return $result;
214  }
215 
219  protected function getBackendUser()
220  {
221  return $GLOBALS['BE_USER'];
222  }
223 }