1: <?php
2: /*****************************************************************************************
3: * X2Engine Open Source Edition is a customer relationship management program developed by
4: * X2Engine, Inc. Copyright (C) 2011-2016 X2Engine Inc.
5: *
6: * This program is free software; you can redistribute it and/or modify it under
7: * the terms of the GNU Affero General Public License version 3 as published by the
8: * Free Software Foundation with the addition of the following permission added
9: * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
10: * IN WHICH THE COPYRIGHT IS OWNED BY X2ENGINE, X2ENGINE DISCLAIMS THE WARRANTY
11: * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
12: *
13: * This program is distributed in the hope that it will be useful, but WITHOUT
14: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15: * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
16: * details.
17: *
18: * You should have received a copy of the GNU Affero General Public License along with
19: * this program; if not, see http://www.gnu.org/licenses or write to the Free
20: * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21: * 02110-1301 USA.
22: *
23: * You can contact X2Engine, Inc. P.O. Box 66752, Scotts Valley,
24: * California 95067, USA. or at email address contact@x2engine.com.
25: *
26: * The interactive user interfaces in modified source and object code versions
27: * of this program must display Appropriate Legal Notices, as required under
28: * Section 5 of the GNU Affero General Public License version 3.
29: *
30: * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
31: * these Appropriate Legal Notices must retain the display of the "Powered by
32: * X2Engine" logo. If the display of the logo is not reasonably feasible for
33: * technical reasons, the Appropriate Legal Notices must display the words
34: * "Powered by X2Engine".
35: *****************************************************************************************/
36:
37: /**
38: * Description of X2ControllerPermissionsBehavior
39: *
40: * @package application.components.permissions
41: */
42: class X2ControllerPermissionsBehavior extends ControllerPermissionsBehavior {
43:
44: /**
45: * Extension of a base Yii function, this method is run before every action
46: * in a controller. If true is returned, it procedes as normal, otherwise
47: * it will redirect to the login page or generate a 403 error.
48: * @param string $action The name of the action being executed.
49: * @return boolean True if the user can procede with the requested action
50: */
51: public function beforeAction($action = null) {
52: if (is_int(Yii::app()->locked) &&
53: !Yii::app()->user->checkAccess('GeneralAdminSettingsTask')) {
54:
55: $this->owner->appLockout();
56: }
57: $auth = Yii::app()->authManager;
58: $params = array();
59: if (empty($action))
60: $action = $this->owner->getAction()->getId();
61: elseif (is_string($action)) {
62: $action = $this->owner->createAction($action);
63: }
64:
65: $actionId = $action->getId();
66:
67: // These actions all have a model provided with them but its assignment
68: // should not be checked for an exception. They either have permission
69: // for this action or they do not.
70: $exceptions = array(
71: 'updateStageDetails',
72: 'deleteList',
73: 'updateList',
74: 'userCalendarPermissions',
75: 'exportList',
76: 'updateLocation'
77: );
78: if (($this->owner->hasProperty('modelClass') || property_exists($this->owner, 'modelClass')) && class_exists($this->owner->modelClass)) {
79: $staticModel = X2Model::model($this->owner->modelClass);
80: }
81:
82: if (isset($_GET['id']) && !in_array($actionId, $exceptions) && !Yii::app()->user->isGuest &&
83: isset($staticModel)) {
84:
85: // Check assignment fields in the current model
86: $retrieved = true;
87: $model = $staticModel->findByPk($_GET['id']);
88: if ($model instanceof X2Model) {
89: $params['X2Model'] = $model;
90: }
91: }
92:
93: // Generate the proper name for the auth item
94: $actionAccess = ucfirst($this->owner->getId()) . ucfirst($actionId);
95: $authItem = $auth->getAuthItem($actionAccess);
96:
97: // Return true if the user is explicitly allowed to do it, or if there is no permission
98: // item, or if they are an admin
99: if (Yii::app()->params->isAdmin ||
100: // access for missing permission item only granted for authenticated users and for
101: // API requests (since API controllers have their own layer of authentication)
102: ((!Yii::app()->user->isGuest ||
103: Yii::app()->controller instanceof ApiController ||
104: Yii::app()->controller instanceof Api2Controller) &&
105: !($authItem instanceof CAuthItem)) ||
106: Yii::app()->user->checkAccess($actionAccess, $params)) {
107:
108: return true;
109: } elseif (Yii::app()->user->isGuest) {
110: Yii::app()->user->returnUrl = Yii::app()->request->url;
111: if (Yii::app()->isMobileApp ()) {
112: $this->owner->redirect($this->owner->createAbsoluteUrl('/mobile/login'));
113: } else {
114: $this->owner->redirect($this->owner->createUrl('/site/login'));
115: }
116: } else {
117: $this->owner->denied();
118: }
119: }
120:
121: /**
122: * Determines if we have permission to view/edit/delete something based on the assignedTo field.
123: *
124: * @param mixed $model The model in question (subclass of {@link CActiveRecord} or
125: * {@link X2Model}
126: * @param string $action
127: * @return boolean
128: */
129: public function checkPermissions(&$model, $action = null) {
130: if (Yii::app()->params->isAdmin) return true;
131:
132: $view = false;
133: $edit = false;
134: $delete = false;
135: $module = $model instanceof X2Model ?
136: Yii::app()->getModule($model->module) : Yii::app()->controller->module;
137: if (isset($module)) {
138: $moduleAdmin = Yii::app()->user->checkAccess(ucfirst($module->name) . 'Admin');
139: } else {
140: $moduleAdmin = false;
141: }
142: if ($model->asa('permissions') != null &&
143: $module instanceof CModule) {
144:
145: // Check assignment and visibility using X2PermissionsBehavior
146: $view = (Yii::app()->params->isAdmin || $moduleAdmin) ||
147: $model->isVisibleTo(Yii::app()->getSuModel());
148: if ($view) { // Only check edit permissions if they're allowed to view
149: $edit = (Yii::app()->params->isAdmin || $moduleAdmin) ||
150: Yii::app()->authManager->checkAccess(
151: ucfirst($module->name) . 'Update',
152: Yii::app()->getSuID(),
153: array('X2Model' => $model)
154: );
155: }
156: if($view){//It's conceivable that a user might be able to delete without being able to edit
157: $delete = (Yii::app()->params->isAdmin || $moduleAdmin) ||
158: Yii::app()->authManager->checkAccess(
159: ucfirst($module->name) . 'Delete',
160: Yii::app()->getSuID(),
161: array('X2Model' => $model)
162: );
163: }
164: } elseif ($model->asa('permissions')) {
165: // Only visibility based permissions are possible
166: $view = $model->isVisibleTo(Yii::app()->getSuModel());
167: $edit = $model->isVisibleTo(Yii::app()->getSuModel());
168: $delete = $model->isVisibleTo(Yii::app()->getSuModel());
169: } else {
170: // No special permissions checks are available
171: $view = true;
172: $edit = true;
173: $delete = true;
174: }
175:
176: if (!isset($action)) // hash of all permissions if none is specified
177: return array('view' => $view, 'edit' => $edit, 'delete' => $delete);
178: elseif ($action == 'view')
179: return $view;
180: elseif ($action == 'edit')
181: return $edit;
182: elseif ($action == 'delete')
183: return $delete;
184: else
185: return false;
186: }
187:
188: /**
189: * Format the left sidebar menu of links to remove items which a user is not
190: * allowed to perform due to role settings.
191: * @param array $array An array of menu items to be formatted
192: * @param array $params An array of special parameters to be used for a role's biz rule
193: * @return array The formatted list of menu items
194: */
195: function formatMenu($array, $params = array()) {
196: $auth = Yii::app()->authManager;
197: foreach ($array as &$item) {
198: if (isset($item['url']) && is_array($item['url'])) {
199: $url = $item['url'][0];
200: if (preg_match('/\//', $url)) {
201: $pieces = explode('/', $url);
202: $action = "";
203: foreach ($pieces as $piece) {
204: $action.=ucfirst($piece);
205: }
206: } else {
207: $action = ucfirst($this->owner->getId() . ucfirst($item['url'][0]));
208: }
209: // For special actions within the Admin controller that use the "checkAdminOn"
210: // biz rule method: add a module parameter for proper checking
211: if($this->owner->getModule() instanceof CModule)
212: $params['module'] = $this->owner->getModule()->getId();
213: $authItem = $auth->getAuthItem($action);
214: if (!isset($item['visible']) || $item['visible'] == true) {
215: $item['visible'] = Yii::app()->params->isAdmin || Yii::app()->user->checkAccess($action, $params) || is_null($authItem);
216: }
217: } else {
218: if (isset($item['linkOptions']['submit'])) {
219: $action = ucfirst($this->owner->getId() . ucfirst($item['linkOptions']['submit'][0]));
220:
221: $authItem = $auth->getAuthItem($action);
222: $item['visible'] = Yii::app()->user->checkAccess($this->owner->getId() . ucfirst($item['linkOptions']['submit'][0]), $params) || is_null($authItem);
223:
224: // Add the CSRF Token to all submit links
225: $item['linkOptions']['csrf'] = true;
226: }
227: }
228: }
229:
230: return $array;
231: }
232:
233: }
234:
235: ?>
236: