security.doxy
1 /*!
2 \page security Security
3 <div class="has-toc"></div>
4 
5 # Security # {#sec_main}
6 
7 Two key aspects of securing an application are _authentication_ and _authorization_.
8 While __authentication__ is the process of verifying the identity of a user,
9 __authorization__ means determining if the user is allowed to do what he or she
10 is about to do. That implies that authentication is a precondition for
11 authorization. Input __validation and filtering__ is another aspect, which is
12 especially important in web applications.
13 
14 ## Users and Roles ## {#sec_users_roles}
15 
16 Users are essential for an authentication system. In wCMF users are represented
17 as instances of classes implementing the
18 \link wcmf::lib::security::principal::User `User`\endlink interface. Since wCMF's
19 authorization system is role based, users are organized in roles. Role classes
20 implement the \link wcmf::lib::security::principal::Role `Role`\endlink interface.
21 A user could have multiple roles, while multiple users could have the
22 same role.
23 
24 The concrete implementations of these interfaces are configured in
25 \link wcmf::lib::security::principal::PrincipalFactory `PrincipalFactory`\endlink.
26 
27 ## Authentication ## {#sec_authentication}
28 
29 In wCMF authentication is handled by implementations of
30 \link wcmf::lib::security::AuthenticationManager `AuthenticationManager`\endlink.
31 
32 By default
33 \link wcmf::lib::security::impl::DefaultAuthenticationManager `DefaultAuthenticationManager`\endlink
34 is used. It implements a __login/password__ based authentication procedure by
35 matching the given user credentials against existing
36 \link wcmf::lib::security::principal::User `User`\endlink instances. These instances
37 are provided by implementations of
38 \link wcmf::lib::security::principal::PrincipalFactory `PrincipalFactory`\endlink.
39 
40 The following code demonstrates the authentication process as implemented
41 in \link wcmf::application::controller::LoginController `LoginController`\endlink:
42 
43 <div class="php">
44 ```
45 // get the user credentials from the request
46 $login = $request->getValue('user');
47 $password = $request->getValue('password');
48 
49 try {
50  // try to login using the credentials
51  $authUser = $this->_authenticationManager->login([
52  'login' => $login,
53  'password' => $password
54  ]);
55 }
56 catch (Exception $ex) {
57  Log::error("Could not log in: ".$ex, __CLASS__);
58 }
59 
60 // set the authenticated user in the session
61 if ($authUser) {
62  // login succeeded
63  $session->setAuthUser($authUser->getLogin());
64 }
65 ```
66 </div>
67 
68 @note The login of the user, that is associated with the current session -
69 the _current user_ - is obtained using the
70 \link wcmf::lib::core::Session::getAuthUser `Session::getAuthUser`\endlink
71 method. Before successful authentication, this login is
72 \link wcmf::lib::security::principal::impl::AnonymousUser::USER_GROUP_NAME `AnonymousUser::USER_GROUP_NAME`\endlink.
73 
74 The configuration of the authentication process in the \ref app "default application"
75 looks like the following:
76 
77 <div class="ini">
78 ```
79 [AuthenticationManager]
80 __class = wcmf\lib\security\impl\DefaultAuthenticationManager
81 principalFactory = $principalFactory
82 
83 [PrincipalFactory]
84 __class = wcmf\lib\security\principal\impl\DefaultPrincipalFactory
85 userType = app.src.model.wcmf.User
86 roleType = app.src.model.wcmf.Role
87 ```
88 </div>
89 
90 Since
91 \link wcmf::lib::security::principal::impl::DefaultPrincipalFactory `DefaultPrincipalFactory`\endlink
92 retrieves user instances from the storage, it needs to configured with the
93 appropriate entity types. If required, the default user type can be replaced
94 by custom implementations of \link wcmf::lib::security::principal::User `User`\endlink.
95 
96 ## Authorization ## {#sec_authorization}
97 
98 The purpose of authorization is controlling access to application resources,
99 which could be controllers or entity instances. To establish __access control__,
100 rules have to be defined in the first place and enforced afterwards.
101 
102 ### Permissions ### {#sec_perm}
103 
104 Access control rules are expressed as _permissions_. Permissions are either
105 granted or denied to a role (see \ref sec_users_roles).
106 
107 A permission definition in wCMF consists of two parts:
108 
109 - The __permission subject__ is a combination of a _resource_, a _context_ and an
110  _action_ and the notation is the same as for action keys (see \ref arch_actionkey),
111  except that the _controller_ value is an arbitrary resource.
112 - The __involved roles__ are listed space-separated and each one is prepended with
113  a _modifier_ (<em>+</em> for granting and <em>-</em> for denying).
114 
115 The following code illustrates the __format__:
116 
117 <div class="ini">
118 ```
119 resource?context?action = +allowedRole -deniedRole ...
120 ```
121 </div>
122 
123 #### Implicit denial ####
124 
125 Roles that are not listed in the permission are denied per default. The wildcard
126 character (<em>*</em>) is used to define the permission for all roles that are
127 not explicitly listed.
128 
129 The following code grants the permission only to _allowedRole_
130 
131 <div class="ini">
132 ```
133 resource?context?action = +allowedRole -*
134 ```
135 </div>
136 
137 and is equivalent to
138 
139 <div class="ini">
140 ```
141 resource?context?action = +allowedRole
142 ```
143 </div>
144 
145 #### Default policy ####
146 
147 If no permissions are defined on a resource, a _default policy_ will be applied by default.
148 \link wcmf::lib::security::impl::AbstractPermissionManager `AbstractPermissionManager`\endlink implements the
149 default policy as follows:
150 
151 - If the current user is __not authorized__, the default policy denies all actions
152 - If the current user is __authorized__, the default policy allows all actions
153 
154 The \link wcmf::lib::security::PermissionManager::authorize `PermissionManager::authorize`\endlink method
155 allows to ignore the default policy by passing `false` as the `$applyDefaultPolicy` parameter, in which
156 case the method returns null, if no permissions are defined for the resource.
157 
158 #### Operator precedence ####
159 
160 Granted roles are evaluated before denied ones. That means that the following
161 code grants the permission to a user who has both roles (_allowedRole_ and _deniedRole_)
162 although the permission is denied for one of the roles.
163 
164 <div class="ini">
165 ```
166 resource?context?action = +allowedRole -deniedRole
167 ```
168 </div>
169 
170 #### Built-in resources ####
171 
172 The resource value could be set to any string to implement custom application
173 specific permissions.
174 
175 Besides this, wCMF uses the following built-in resources:
176 
177 - _Controller_ to restrict access on execution of a controller
178  (e.g. `wcmf\application\controller\SaveController`)
179 - _Entity type_ to restrict access on all instances of an entity type
180  (e.g. `app.src.model.wcmf.User`)
181 - _Entity property_ to restrict access on a certain property of an entity type
182  (e.g. `app.src.model.wcmf.User.login`)
183 - _Entity instance_ to restrict access on one entity instance
184  (e.g. `app.src.model.wcmf.User:123`)
185 - _Entity instance propery_ to restrict access on a certain property of one
186  entity instance (e.g. `app.src.model.wcmf.User:123.login`)
187 - _Media_ to restrict access to file resources
188  (e.g. `media:/folderA??hidden`)
189 
190 The __actions for the persistency related resources__ are properties of
191 \link wcmf::lib::persistence::PersistenceAction `PersistenceAction`\endlink,
192 e.g. \link wcmf::lib::persistence::PersistenceAction::READ `PersistenceAction::READ`\endlink.
193 While all actions can be applied to instances, for properties only _read_ and _update_
194 are taken into account.
195 
196 @note __Entity relations__ are treated like entity properties, which means that read and update
197 access can be restricted.
198 
199 The __actions for the file related resources__ are _read_, _write_, _locked_ (read only) and _hidden_.
200 
201 #### Dynamic roles ####
202 
203 Besides assigning _static roles_ to users, it's sometimes useful to have roles, that evaluate
204 dynamically in the current context (_requested resource_, _user_ and _action_). With these
205 so called _dynamic roles_ it is for example possible to assign permissions to the creator of
206 an instance or realize date/time based permissions.
207 
208 Dynamic roles implement the \link wcmf::lib::security::principal::DynamicRole `DynamicRole`\endlink
209 interface and are defined in the `DynamicRoles` configuration section.
210 
211 The following example shows the configuration of the
212 \link wcmf::lib::security::principal::impl::CreatorRole `CreatorRole`\endlink in
213 the \ref app "default application":.
214 
215 <div class="ini">
216 ```
217 [DynamicRoles]
218 creator = $creatorRole
219 
220 [CreatorRole]
221 __class = wcmf\lib\security\principal\impl\CreatorRole
222 ```
223 </div>
224 
225 @note Dynamic roles are checked before static role assignments. That means you
226 could define a dynamic role with the same name as a static role and add custom
227 matching code.
228 
229 #### Permission inheritance ####
230 
231 Permissions on __entity instances__ are passed to child entities in a _composite
232 relation_ (see \ref model_associations). The following image illustrates this:
233 
234 \image html permission-inheritance.png "Permission inheritance"
235 
236 If access to the `Book` instance _Book A_ is restricted for one role, the same
237 restriction also applies for the `Chapter` instances belonging to it
238 (_Chapter A1_, _Chapter A2_). An inherited access restriction can be removed by
239 explicitly granting the permission on the object in question.
240 
241 #### Examples ####
242 
243 The following code shows some permission examples:
244 
245 <div class="ini">
246 ```
247 # tester role is not allowed to update any authors except for the specified one
248 # tester role is not allowed to update any authors stage attribute
249 app.src.model.Author??update = -tester
250 app.src.model.Author:111??update = +tester
251 app.src.model.Author.stage??update = +administrators
252 
253 # tester role is not allowed to update any publishers name except for the specified one
254 # tester role is not allowed to update any authors stage attribute
255 app.src.model.Publisher.name??update = -tester
256 app.src.model.Publisher:111.name??update = +tester
257 
258 # tester role is not allowed to read any book name except for the specified one
259 app.src.model.Book??read = -tester
260 app.src.model.Book:111??read = +tester
261 
262 # tester is not allowed to read chapter 111 and due to inheritance also not sub chapter 222,
263 # and sub sub chapter 333, sub chapter 555 explicitly allowed and due to inheritance
264 # also sub sub chapter 666
265 app.src.model.Chapter:111??read = -tester +administrators
266 app.src.model.Chapter:555??read = +tester +administrators
267 
268 # tester role is not allowed to execute SaveController
269 wcmf\application\controller\SaveController?? = -tester
270 
271 # the tmp directory is hidden for everyone
272 # only administrators can rename or delete the uploads directory
273 media:/tmp??hidden = +*
274 media:/uploads??locked = -administrators +*
275 
276 # custom permissions
277 customPermission??start = +tester
278 customPermission??stop = -tester
279 ```
280 </div>
281 
282 ### Permission management ### {#sec_perm_manage}
283 
284 Permission management includes _creation_, _modification_ and _deletion_ of permissions
285 as well as handling _authorization requests_. In an wCMF application an instance
286 of \link wcmf::lib::security::PermissionManager `PermissionManager`\endlink is
287 used for these tasks. It is configured in the `PermissionManager` configuration
288 section.
289 
290 Generally there are two kinds of permissions to be defined in an application.
291 
292 - _Static permissions_ are already known when the application is designed,
293  e.g. restriction to entity types or controllers. Since these permissions are
294  not likely to be changed by application users, they can be stored in the
295  application configuration.
296 - _Dynamic permissions_ are defined on the application data. These permissions
297  will be set when the appropriate data is created. To allow application users
298  to change these permissions they are typically stored in the database.
299 
300 Different permission types require different ways of permission management,
301 particularly regarding storing permissions. To support this wCMF provides
302 several implementations of the
303 \link wcmf::lib::security::PermissionManager `PermissionManager`\endlink interface:
304 
305 - \link wcmf::lib::security::impl::StaticPermissionManager `StaticPermissionManager`\endlink
306  is used to retrieve permissions from the application configuration. The
307  permissions are stored in the `Authorization` configuration section like shown
308  in the following code:
309 
310 <div class="ini">
311 ```
312 [Authorization]
313 ??login = +*
314 ??logout = +*
315 ??checkPermissions = +*
316 ??checkPermissionsOfUser = +administrators
317 app.src.model.wcmf.User??read = +administrators
318 app.src.model.wcmf.User??update = +administrators
319 app.src.model.wcmf.User??delete = +administrators
320 app.src.model.wcmf.User??create = +administrators
321 ```
322 </div>
323 
324 - \link wcmf::lib::security::impl::DefaultPermissionManager `DefaultPermissionManager`\endlink
325  handles permissions that are stored in the database. The entity type that actually
326  stores the permissions is required to have a _resource_, _context_, _action_
327  and _roles_ attribute and is defined in the application configuration. The
328  following lines are taken from the configuration of the \ref app "default application":
329 
330 <div class="ini">
331 ```
332 [DefaultPermissionManager]
333 __class = wcmf\lib\security\impl\DefaultPermissionManager
334 permissionType = app.src.model.wcmf.Permission
335 ```
336 </div>
337 
338 - \link wcmf::lib::security::impl::ChainedPermissionManager `ChainedPermissionManager`\endlink
339  is used to combine different
340  \link wcmf::lib::security::PermissionManager `PermissionManager`\endlink instances.
341  When asked for authorization, it delegates the request to all it's managers, while
342  creation, modification and deletion of permissions is always handled by the
343  first contained manager. An example configuration of this manager is shown in
344  the code below:
345 
346 <div class="ini">
347 ```
348 [PermissionManager]
349 __class = wcmf\lib\security\impl\ChainedPermissionManager
350 managers = {$defaultPermissionManager, $staticPermissionManager}
351 
352 [DefaultPermissionManager]
353 __class = wcmf\lib\security\impl\DefaultPermissionManager
354 permissionType = app.src.model.wcmf.Permission
355 
356 [StaticPermissionManager]
357 __class = wcmf\lib\security\impl\StaticPermissionManager
358 ```
359 </div>
360 
361 - \link wcmf::lib::security::impl::NullPermissionManager `NullPermissionManager`\endlink
362  acts like there is no permission manager and is merely used for testing.
363 
364 All implementations inherit from
365 \link wcmf::lib::security::impl::AbstractPermissionManager `AbstractPermissionManager`\endlink,
366 which already provides most of parts for handling authorization requests.
367 
368 #### Temporary permissions #### {#sec_perm_temp}
369 
370 There are situations, where a piece of code requires a certain permission in the
371 context of the current user, which is not possible to grant throughout the whole
372 application. For example, if a user wants to sign in to the application,
373 \link wcmf::lib::security::principal::PrincipalFactory `PrincipalFactory`\endlink
374 needs to provide a user instance although the anonymous user is not allowed
375 to read user instances. To accomplish this,
376 \link wcmf::lib::security::PermissionManager `PermissionManager`\endlink allows
377 to set a transient, temporary permission like in the following example:
378 
379 <div class="php">
380 ```
381 $permissionManager = ObjectFactory::getInstance('permissionManager');
382 $persistenceFacade = ObjectFactory::getInstance('persistenceFacade');
383 $userType = 'app.src.model.wcmf.User';
384 
385 // set up a temporary permission to read the user instance for the given login
386 $permissionManager->addTempPermission($userType, '', PersistenceAction::READ);
387 
388 $user = $persistenceFacade->loadFirstObject($userType, BuildDepth::SINGLE, [
389  new Criteria($userType, 'login', '=', $login)
390  ], null);
391 
392 // remove the temporary permission
393 $permissionManager->removeTempPermission($userType, '', PersistenceAction::READ);
394 ```
395 </div>
396 
397 ### Checking permissions ### {#sec_perm_check}
398 
399 To test, if a user has the permission to access a resource in the requested way
400 the method
401 \link wcmf::lib::security::PermissionManager::authorize `PermissionManager::authorize`\endlink
402 is used. It returns a boolean value indicating whether the user is authorized
403 or not.
404 
405 The following code shows how to determine, if the current user is allowed to read
406 the given object:
407 
408 <div class="php">
409 ```
410 $canRead = $permissionManager->authorize($object->getOID(), '', PersistenceAction::READ);
411 ```
412 </div>
413 
414 #### Default policies #### {#sec_perm_default_policies}
415 
416 Default policies answer the question, what happens if __no permission__ is defined
417 on a requested resource. These rules depend on the authentication status of the
418 current user and are defined in
419 \link wcmf::lib::security::impl::AbstractPermissionManager `AbstractPermissionManager`\endlink
420 as follows:
421 
422 - _Not authenticated_: Resource is _not accessible_
423 - _Authenticated_: Resource is _accessible_
424 
425 ## Sessions ## {#sec_session}
426 
427 wCMF provides the following \link wcmf::lib::core::Session `Session`\endlink
428 implementations:
429 
430 - \link wcmf::lib::core::impl::DefaultSession `DefaultSession`\endlink is a session
431  that uses PHP's default server side session implementation in combination with a
432  session cookie.
433 - \link wcmf::lib::core::impl::AuthTokenSession `AuthTokenSession`\endlink additionally
434  requires clients to send an `X-Auth-Token` request header.
435 - \link wcmf::lib::core::impl::ClientSideSession `ClientSideSession`\endlink has
436  no server state as it stores the data in cookies.
437 
438 ## Input ## {#sec_input}
439 
440 Generally all external input sent to the application should be considered harmful.
441 
442 In PHP this input is stored in so called _Superglobals_, e.g. <em>$_GET</em>,
443 <em>$_POST</em>, <em>$_FILES</em>. To avoid using these global variables directly
444 in code, wCMF encapsulates them in the
445 \link wcmf::lib::presentation::Request `Request`\endlink instance and makes
446 them available through the
447 \link wcmf::lib::presentation::Request::getValue `Request::getValue`\endlink
448 method. Besides the variable name this method defines the following optional
449 parameters:
450 
451 - `$default` default value if the value is not contained in the request
452 - `$validateDesc` description of the validation to be applied to the value
453 
454 The `$validateDesc` parameter is passed to the
455 \link wcmf::lib::validation::Validator::validate `Validator::validate`\endlink method
456 and `null` is returned if validation fails.
457 
458 The following code demonstrates the usage:
459 
460 <div class="php">
461 ```
462 // validate an email value
463 $email = $request->getValue('email', '', 'filter:{"type":"validate_email"}');
464 
465 // validate a date using a regular expression and return the current date on failure
466 $today = date('Y-m-d');
467 $date = $request->getValue('date', $today, 'regex:{"pattern":"/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/"}');
468 ```
469 </div>
470 
471 For more information about validation see \ref pers_validation.
472 
473 ### CSRF protection ### {#sec_input_csrf}
474 
475 To avoid [CSRF](https://en.wikipedia.org/wiki/Cross-site_request_forgery) vulnerabilities
476 in a web application, forms are usually protected by using _CSRF tokens_. The
477 \link wcmf::lib::presentation::Controller::generateCsrfToken `Controller::generateCsrfToken`\endlink
478 method is used to generate a unique token value for each form display. The token is validated by using the
479 \link wcmf::lib::presentation::Controller::validateCsrfToken `Controller::validateCsrfToken`\endlink
480 method when the form is submitted. For proper identification, tokens are referenced by a
481 name (e.g. the form's name) which is passed to these methods.
482 
483 The following example demonstrates the usage of these methods.
484 
485 A new token value is generated each time the form is displayed:
486 
487 <div class="php">
488 ```
489 class UserController {
490 
491  public function render() {
492 
493  $this->generateCsrfToken('login');
494 
495  }
496 }
497 ```
498 </div>
499 
500 This creates the `csrf_token` response variable. The variable is used to add
501 the token as a hidden field to the form:
502 
503 <div class="html">
504 ```
505 <input type="hidden" name="csrf_token" value="{$csrf_token}">
506 ```
507 </div>
508 
509 After form submission the controller validates the token and acts appropriately:
510 
511 <div class="php">
512 ```
513 class UserController {
514 
515  public function login() {
516 
517  if (!$this->validateCsrfToken('login')) {
518  // error
519  }
520  else {
521  // do login
522  }
523 
524  }
525 }
526 ```
527 </div>
528 */