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