|
1
|
|
|
<?php declare(strict_types=1); |
|
2
|
|
|
/** |
|
3
|
|
|
* Created by PhpStorm. |
|
4
|
|
|
* User: egorov |
|
5
|
|
|
* Date: 17.07.2015 |
|
6
|
|
|
* Time: 9:20 |
|
7
|
|
|
*/ |
|
8
|
|
|
namespace samsoncms\app\security; |
|
9
|
|
|
|
|
10
|
|
|
use samson\activerecord\dbQuery; |
|
11
|
|
|
use samson\activerecord\groupright; |
|
12
|
|
|
use samsonframework\containerannotation\Inject; |
|
13
|
|
|
use samsonframework\containerannotation\Injectable; |
|
14
|
|
|
use samsonframework\containerannotation\InjectArgument; |
|
15
|
|
|
use samsonframework\core\ResourcesInterface; |
|
16
|
|
|
use samsonframework\core\SystemInterface; |
|
17
|
|
|
use samsonframework\i18n\i18nInterface; |
|
18
|
|
|
use samsonframework\orm\QueryInterface; |
|
19
|
|
|
|
|
20
|
|
|
/** |
|
21
|
|
|
* SamsonCMS security controller |
|
22
|
|
|
* @package samsoncms\security |
|
23
|
|
|
*/ |
|
24
|
|
|
class Controller extends \samsoncms\Application |
|
25
|
|
|
{ |
|
26
|
|
|
/** Application access right name pattern */ |
|
27
|
|
|
const RIGHT_APPLICATION_KEY = '/^APPLICATION_(?<application>.*)/ui'; |
|
28
|
|
|
|
|
29
|
|
|
/** @var array User group rights cache */ |
|
30
|
|
|
protected $rightsCache = array(); |
|
31
|
|
|
|
|
32
|
|
|
/** Application name */ |
|
33
|
|
|
public $name = 'Права'; |
|
34
|
|
|
|
|
35
|
|
|
/** Application description */ |
|
36
|
|
|
public $description = 'Права доступа'; |
|
37
|
|
|
|
|
38
|
|
|
/** Application icon*/ |
|
39
|
|
|
public $icon = 'unlock'; |
|
40
|
|
|
|
|
41
|
|
|
/** Identifier */ |
|
42
|
|
|
public $id = 'security'; |
|
43
|
|
|
|
|
44
|
|
|
public $dbGroupIdField = 'group_id'; |
|
45
|
|
|
|
|
46
|
|
|
/** @var string Module identifier */ |
|
47
|
|
|
protected $entity = '\samson\activerecord\group'; |
|
48
|
|
|
|
|
49
|
|
|
/** @var string SamsonCMS application form class */ |
|
50
|
|
|
protected $formClassName = '\samsoncms\app\security\Form'; |
|
51
|
|
|
|
|
52
|
|
|
/** @var QueryInterface Database query instance */ |
|
53
|
|
|
protected $query; |
|
54
|
|
|
|
|
55
|
|
|
/** |
|
56
|
|
|
* @var \samsonframework\i18n\i18nInterface |
|
57
|
|
|
* @Injectable |
|
58
|
|
|
*/ |
|
59
|
|
|
protected $i18n; |
|
60
|
|
|
|
|
61
|
|
|
//[PHPCOMPRESSOR(remove,start)] |
|
62
|
|
|
public function prepare() |
|
63
|
|
|
{ |
|
64
|
|
|
$social = & $this->system->module('social'); |
|
65
|
|
|
//db()->createField($this, $social->dbTable, 'dbGroupIdField', 'INT(11)'); |
|
66
|
|
|
|
|
67
|
|
|
$adminUser = '[email protected]'; |
|
68
|
|
|
|
|
69
|
|
|
// Try to find generic user |
|
70
|
|
|
$admin = $this->query |
|
71
|
|
|
->entity($social->dbTable) |
|
72
|
|
|
->where($social->dbEmailField, $adminUser) |
|
73
|
|
|
->first(); |
|
74
|
|
|
|
|
75
|
|
|
// Add admin group id value |
|
76
|
|
|
if (isset($admin)&&($admin[$this->dbGroupIdField] != 1)) { |
|
77
|
|
|
$admin[$this->dbGroupIdField] = 1; |
|
78
|
|
|
$admin->save(); |
|
|
|
|
|
|
79
|
|
|
} |
|
80
|
|
|
return parent::prepare(); |
|
81
|
|
|
} |
|
82
|
|
|
//[PHPCOMPRESSOR(remove,end)] |
|
83
|
|
|
|
|
84
|
|
|
/** |
|
85
|
|
|
* Asynchronous change group right controller action |
|
86
|
|
|
* @param string $groupID Group identifier |
|
87
|
|
|
* @param string $rightID Right identifier |
|
88
|
|
|
* @return array Asynchronous response array |
|
89
|
|
|
*/ |
|
90
|
|
|
public function __async_change($groupID, $rightID) |
|
|
|
|
|
|
91
|
|
|
{ |
|
92
|
|
|
$group = null; |
|
93
|
|
|
if($this->findEntityByID($groupID, $group)) { |
|
|
|
|
|
|
94
|
|
|
$right = null; |
|
95
|
|
|
if($this->findEntityByID($rightID, $right, 'right')) { |
|
|
|
|
|
|
96
|
|
|
/** @var \samsonframework\orm\Record Try to find this right for a specific group */ |
|
97
|
|
|
$groupRight = null; |
|
98
|
|
|
if ($this->query->className('groupright')->cond('GroupID', $groupID)->cond('RightID', $rightID)->first($groupRight)) { |
|
|
|
|
|
|
99
|
|
|
// Remove existing |
|
100
|
|
|
$groupRight->delete(); |
|
|
|
|
|
|
101
|
|
|
} else { // Create new |
|
102
|
|
|
$groupRight = new groupright(); |
|
103
|
|
|
$groupRight->Active = 1; |
|
104
|
|
|
$groupRight->GroupID = $groupID; |
|
105
|
|
|
$groupRight->RightID = $rightID; |
|
106
|
|
|
$groupRight->save(); |
|
107
|
|
|
} |
|
108
|
|
|
|
|
109
|
|
|
return array('status' => '1'); |
|
110
|
|
|
} |
|
111
|
|
|
|
|
112
|
|
|
return array('status' => '0', 'error' => 'Right #'.$rightID.' was not found'); |
|
113
|
|
|
} |
|
114
|
|
|
|
|
115
|
|
|
return array('status' => '0', 'error' => 'Group #'.$rightID.' was not found'); |
|
116
|
|
|
} |
|
117
|
|
|
|
|
118
|
|
|
/** |
|
119
|
|
|
* Core routing(core.routing) event handler |
|
120
|
|
|
* @param \samson\core\Core $core |
|
121
|
|
|
* @param boolean $securityResult |
|
122
|
|
|
* @return boolean True if security passed |
|
123
|
|
|
*/ |
|
124
|
|
|
public function handle(&$core, &$securityResult) |
|
125
|
|
|
{ |
|
126
|
|
|
// Remove URL base from current URL, split by '/' |
|
127
|
|
|
$parts = explode(__SAMSON_BASE__, $_SERVER['REQUEST_URI']); |
|
128
|
|
|
$parts = array_values(array_filter($parts)); |
|
129
|
|
|
$cmsUrl = isset($parts[0]) ? $parts[0] : ''; |
|
130
|
|
|
|
|
131
|
|
|
if ($cmsUrl == $core->module('cms')->baseUrl) { |
|
132
|
|
|
// Get module identifier |
|
133
|
|
|
$module = isset($parts[1]) ? $parts[1] : ''; |
|
134
|
|
|
|
|
135
|
|
|
// Get action identifier |
|
136
|
|
|
//$action = isset($parts[1]) ? $parts[1] : ''; |
|
137
|
|
|
// Get parameter values collection |
|
138
|
|
|
//$params = sizeof($parts) > 2 ? array_slice($parts, 2) : array(); |
|
139
|
|
|
$social = & $this->system->module('social'); |
|
140
|
|
|
|
|
141
|
|
|
// If we have are authorized |
|
142
|
|
|
if ($social->authorized()) { |
|
143
|
|
|
/**@var \samson\activerecord\user Get authorized user object */ |
|
144
|
|
|
$authorizedUser = $social->user(); |
|
145
|
|
|
|
|
146
|
|
|
$dbTable = $social->dbTable; |
|
147
|
|
|
$groupIdField = $dbTable::$fieldIDs[$this->dbGroupIdField]; |
|
148
|
|
|
|
|
149
|
|
|
// Try to load security group rights from cache |
|
150
|
|
|
$userRights = & $this->rightsCache[$authorizedUser->$groupIdField]; |
|
151
|
|
|
if (!isset($userRights)) { |
|
152
|
|
|
// Parse security group rights and store it to cache |
|
153
|
|
|
$userRights = $this->parseGroupRights($authorizedUser->$groupIdField); |
|
154
|
|
|
} |
|
155
|
|
|
|
|
156
|
|
|
// Hide all applications except with access rights |
|
157
|
|
|
foreach (self::$loaded as $application) { |
|
158
|
|
|
if (!in_array($application->id, $userRights['application']) |
|
159
|
|
|
&& !in_array(Right::APPLICATION_ACCESS_ALL, $userRights['application']) |
|
160
|
|
|
&& $authorizedUser->$groupIdField != 1 |
|
161
|
|
|
) { |
|
162
|
|
|
$application->hide = true; |
|
163
|
|
|
} |
|
164
|
|
|
} |
|
165
|
|
|
|
|
166
|
|
|
// If we have full right to access all applications or admin |
|
167
|
|
|
if (in_array(Right::APPLICATION_ACCESS_ALL, $userRights['application']) || $authorizedUser->$groupIdField == 1) { |
|
168
|
|
|
return $securityResult = true; |
|
169
|
|
|
} else if (in_array($module, $userRights['application'])) { // Try to find right to access current application |
|
170
|
|
|
return $securityResult = true; |
|
171
|
|
|
} else if ($module == '' && in_array('template', $userRights['application'])) {// Main page(empty url) |
|
172
|
|
|
return $securityResult = true; |
|
173
|
|
|
} else { // We cannot access this application |
|
174
|
|
|
return $securityResult = false; |
|
175
|
|
|
} |
|
176
|
|
|
} |
|
177
|
|
|
} else { |
|
178
|
|
|
return $securityResult = true; |
|
179
|
|
|
} |
|
180
|
|
|
|
|
181
|
|
|
} |
|
182
|
|
|
|
|
183
|
|
|
/** |
|
184
|
|
|
* Parse application access right |
|
185
|
|
|
* @param string $rightName Right name |
|
186
|
|
|
* @return string Application name |
|
187
|
|
|
*/ |
|
188
|
|
|
private function matchApplicationAccessRight($rightName, &$applicationName) |
|
189
|
|
|
{ |
|
190
|
|
|
// Parse application access rights |
|
191
|
|
|
$matches = array(); |
|
192
|
|
|
if (preg_match(Right::APPLICATION_ACCESS_PATTERN, $rightName, $matches)) { |
|
193
|
|
|
// Return application name |
|
194
|
|
|
$applicationName = strtolower($matches['application']); |
|
195
|
|
|
return true; |
|
196
|
|
|
} |
|
197
|
|
|
|
|
198
|
|
|
return false; |
|
199
|
|
|
} |
|
200
|
|
|
|
|
201
|
|
|
/** |
|
202
|
|
|
* Clear all database security rights records that do not match current application list |
|
203
|
|
|
* @param array $accessibleApplications Collection of loaded applications |
|
204
|
|
|
*/ |
|
205
|
|
|
private function clearUnmatchedRights(array $accessibleApplications) |
|
|
|
|
|
|
206
|
|
|
{ |
|
207
|
|
|
// Go throw all rights and remove unnecessary |
|
208
|
|
|
foreach ($this->query->className('right')->exec() as $right) { |
|
|
|
|
|
|
209
|
|
|
// Match application access rights |
|
210
|
|
|
$applicationID = ''; |
|
211
|
|
|
if ($this->matchApplicationAccessRight($right->Name, $applicationID)) { |
|
212
|
|
|
// If there is no such application that access right exists |
|
213
|
|
|
if(!isset($accessibleApplications[$applicationID])) { |
|
|
|
|
|
|
214
|
|
|
$right->delete(); |
|
215
|
|
|
} |
|
216
|
|
|
} |
|
217
|
|
|
} |
|
218
|
|
|
} |
|
219
|
|
|
|
|
220
|
|
|
/** |
|
221
|
|
|
* Parse database application user group rights |
|
222
|
|
|
* @param integer $groupID Security group identifier |
|
223
|
|
|
* @return array Parsed user group rights |
|
224
|
|
|
*/ |
|
225
|
|
|
public function parseGroupRights($groupID) |
|
226
|
|
|
{ |
|
227
|
|
|
/** @var array $parsedRights Parsed rights */ |
|
228
|
|
|
$parsedRights = array('application' => array()); |
|
229
|
|
|
|
|
230
|
|
|
/** @var \samsonframework\orm\Record[] $groupRights Collection of user rights */ |
|
231
|
|
|
$groupRights = array(); |
|
232
|
|
|
// Retrieve all user group rights |
|
233
|
|
|
if ($this->query->className('groupright')->join('right')->cond('GroupID', $groupID)->exec($groupRights)) { |
|
|
|
|
|
|
234
|
|
|
// Iterate all group rights |
|
235
|
|
|
foreach ($groupRights as $groupRight) { |
|
236
|
|
|
// If we have rights for this group |
|
237
|
|
|
if (isset($groupRight->onetomany['_right'])) { |
|
|
|
|
|
|
238
|
|
|
foreach ($groupRight->onetomany['_right'] as $userRight) { |
|
|
|
|
|
|
239
|
|
|
// Parse application access rights |
|
240
|
|
|
$applicationID = ''; |
|
241
|
|
|
if ($this->matchApplicationAccessRight($userRight->Name, $applicationID)) { |
|
242
|
|
|
$parsedRights['application'][] = $applicationID; |
|
243
|
|
|
} |
|
244
|
|
|
} |
|
245
|
|
|
} |
|
246
|
|
|
} |
|
247
|
|
|
} |
|
248
|
|
|
|
|
249
|
|
|
return $parsedRights; |
|
250
|
|
|
} |
|
251
|
|
|
|
|
252
|
|
|
/** Application initialization */ |
|
253
|
|
|
public function init(array $params = array()) |
|
254
|
|
|
{ |
|
255
|
|
|
// Find all applications that needs access rights to it |
|
256
|
|
|
$accessibleApplications = array( |
|
257
|
|
|
'template' => $this->i18n->translate('Главная страница'), // Main application |
|
258
|
|
|
Right::APPLICATION_ACCESS_ALL => Right::APPLICATION_ACCESS_ALL // All application |
|
259
|
|
|
); |
|
260
|
|
|
|
|
261
|
|
|
// Iterate all loaded applications |
|
262
|
|
|
foreach (self::$loaded as $application) { |
|
263
|
|
|
// Iterate only applications with names |
|
264
|
|
|
$accessibleApplications[$application->id] = $application->name; |
|
265
|
|
|
} |
|
266
|
|
|
|
|
267
|
|
|
// Iterate all applications that needs access rights |
|
268
|
|
|
foreach ($accessibleApplications as $accessibleApplicationID => $accessibleApplicationName) { |
|
269
|
|
|
// Try to find this right in db |
|
270
|
|
|
if (!$this->query->className('right')->cond('Name', Right::APPLICATION_ACCESS_TEMPLATE.$accessibleApplicationID)->first() |
|
|
|
|
|
|
271
|
|
|
&& isset($accessibleApplicationName{0}) // Name not empty |
|
272
|
|
|
) { |
|
273
|
|
|
$right = new Right(); |
|
274
|
|
|
$right->Name = Right::APPLICATION_ACCESS_TEMPLATE.strtoupper($accessibleApplicationID); |
|
275
|
|
|
$right->Description = $accessibleApplicationID != Right::APPLICATION_ACCESS_ALL |
|
276
|
|
|
? $this->i18n->translate('Доступ к приложению').' "'.$accessibleApplicationName.'"' |
|
277
|
|
|
: $this->i18n->translate('Полный доступ ко всем приложениям'); |
|
278
|
|
|
$right->Active = 1; |
|
279
|
|
|
$right->save(); |
|
280
|
|
|
} |
|
281
|
|
|
} |
|
282
|
|
|
|
|
283
|
|
|
// Subscribe to core security event |
|
284
|
|
|
\samsonphp\event\Event::subscribe('core.security', array($this, 'handle')); |
|
285
|
|
|
} |
|
286
|
|
|
} |
|
287
|
|
|
|
Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.