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 ~~~~~~~~~~~~~{.php}
44 // get the user credentials from the request
45 $login = $request->getValue('user');
46 $password = $request->getValue('password');
47 
48 try {
49  // try to login using the credentials
50  $authUser = $this->_authenticationManager->login($login, $password);
51 }
52 catch (Exception $ex) {
53  Log::error("Could not log in: ".$ex, __CLASS__);
54 }
55 
56 // set the authenticated user in the session
57 if ($authUser) {
58  // login succeeded
59  $session->setAuthUser($authUser);
60 }
61 ~~~~~~~~~~~~~
62 
63 @note The user, that is associated with the current session - the _current user_ -
64 is obtained using the
65 \link wcmf::lib::core::Session::getAuthUser `Session::getAuthUser`\endlink
66 method. Before successful authentication, this user is an instance of
67 \link wcmf::lib::security::principal::impl::AnonymousUser `AnonymousUser`\endlink.
68 It will be replaced by an instance of the application's
69 \link wcmf::lib::security::principal::User `User`\endlink type after successful
70 authentication.
71 
72 The configuration of the authentication process in the \ref app "default application"
73 looks like the following:
74 
75 ~~~~~~~~~~~~~{.ini}
76 [AuthenticationManager]
77 __class = wcmf\lib\security\impl\DefaultAuthenticationManager
78 principalFactory = $principalFactory
79 
80 [PrincipalFactory]
81 __class = wcmf\lib\security\principal\impl\DefaultPrincipalFactory
82 userType = app.src.model.wcmf.User
83 roleType = app.src.model.wcmf.Role
84 ~~~~~~~~~~~~~
85 
86 Since
87 \link wcmf::lib::security::principal::impl::DefaultPrincipalFactory `DefaultPrincipalFactory`\endlink
88 retrieves user instances from the storage, it needs to configured with the
89 appropriate entity types. If required, the default user type may be replaced
90 by custom implementations of \link wcmf::lib::security::principal::User `User`\endlink.
91 
92 ## Authorization ## {#sec_authorization}
93 
94 The purpose of authorization is controlling access to application resources,
95 which could be controllers or entity instances. To establish __access control__,
96 rules have to be defined in the first place and enforced afterwards.
97 
98 ### Permissions ### {#sec_perm}
99 
100 Access control rules are expressed as _permissions_. Permissions are either
101 granted or denied to a role (see \ref sec_users_roles).
102 
103 A permission definition in wCMF consists of two parts:
104 
105 - The __permission subject__ is a combination of a _resource_, a _context_ and an
106  _action_ and the notation is the same as for action keys (see \ref arch_actionkey),
107  except that the _controller_ value is an arbitrary resource.
108 - The __involved roles__ are listed space-separated and each one is prepended with
109  a _modifier_ (<em>+</em> for granting and <em>-</em> for denying).
110 
111 The following code illustrates the __format__:
112 
113 ~~~~~~~~~~~~~{.ini}
114 resource?context?action = +allowedRole -deniedRole ...
115 ~~~~~~~~~~~~~
116 
117 #### Implicit denial ####
118 
119 Roles that are not listed in the permission are denied per default. The wildcard
120 character (<em>*</em>) is used to define the permission for all roles that are
121 not explicitly listed.
122 
123 The following code grants the permission only to _allowedRole_
124 
125 ~~~~~~~~~~~~~{.ini}
126 resource?context?action = +allowedRole -*
127 ~~~~~~~~~~~~~
128 
129 and is equivalent to
130 
131 ~~~~~~~~~~~~~{.ini}
132 resource?context?action = +allowedRole
133 ~~~~~~~~~~~~~
134 
135 #### Built-in resources ####
136 
137 The resource value could be set to any string to implement custom application
138 specific permissions.
139 
140 Besides this, wCMF uses the following built-in resources:
141 
142 - _Controller_ to restrict access on execution of a controller
143  (e.g. `wcmf\application\controller\SaveController`)
144 - _Entity type_ to restrict access on all instances of an entity type
145  (e.g. `app.src.model.wcmf.User`)
146 - _Entity property_ to restrict access on a certain property of an entity type
147  (e.g. `app.src.model.wcmf.User.login`)
148 - _Entity instance_ to restrict access on one entity instance
149  (e.g. `app.src.model.wcmf.User:123`)
150 - _Entity instance propery_ to restrict access on a certain property of one
151  entity instance (e.g. `app.src.model.wcmf.User:123.login`)
152 
153 The actions for the persistency related resources are properties of
154 \link wcmf::lib::persistence::PersistenceAction `PersistenceAction`\endlink,
155 e.g. \link wcmf::lib::persistence::PersistenceAction::READ `PersistenceAction::READ`\endlink.
156 
157 #### Permission inheritance ####
158 
159 Permissions on __entity instances__ are passed to child entities in a _composite
160 relation_ (see \ref model_associations). The following image illustrates this:
161 
162 \image html permission-inheritance.png "Permission inheritance"
163 
164 If access to the `Book` instance _Book A_ is restricted for one role, the same
165 restriction also applies for the `Chapter` instances belonging to it
166 (_Chapter A1_, _Chapter A2_). An inherited access restriction can be removed by
167 explicitly granting the permission on the object in question.
168 
169 #### Examples ####
170 
171 The following code shows some permission examples:
172 
173 ~~~~~~~~~~~~~{.ini}
174 // tester role is not allowed to update any authors except for the specified one
175 // tester role is not allowed to update any authors stage attribute
176 app.src.model.Author??update = -tester
177 app.src.model.Author:111??update = +tester
178 app.src.model.Author.stage??update = +administrators
179 
180 // tester role is not allowed to update any publishers name except for the specified one
181 // tester role is not allowed to update any authors stage attribute
182 app.src.model.Publisher.name??update = -tester
183 app.src.model.Publisher:111.name??update = +tester
184 
185 // tester role is not allowed to read any book name except for the specified one
186 app.src.model.Book??read = -tester
187 app.src.model.Book:111??read = +tester
188 
189 // tester is not allowed to read chapter 111 and due to inheritance also not sub chapter 222,
190 // and sub sub chapter 333, sub chapter 555 explicitly allowed and due to inheritance
191 // also sub sub chapter 666
192 app.src.model.Chapter:111??read = -tester +administrators
193 app.src.model.Chapter:555??read = +tester +administrators
194 
195 // tester role is not allowed to execute SaveController
196 wcmf\application\controller\SaveController?? = -tester
197 
198 // custom permissions
199 customPermission??start = +tester
200 customPermission??stop = -tester
201 ~~~~~~~~~~~~~
202 
203 ### Permission management ### {#sec_perm_manage}
204 
205 Permission management includes _creation_, _modification_ and _deletion_ of permissions
206 as well as handling _authorization requests_. In an wCMF application an instance
207 of \link wcmf::lib::security::PermissionManager `PermissionManager`\endlink is
208 used for these tasks. It is configured in the `PermissionManager` configuration
209 section.
210 
211 Generally there are two kinds of permissions to be defined in an application.
212 
213 - _Static permissions_ are already known when the application is designed,
214  e.g. restriction to entity types or controllers. Since these permissions are
215  not likely to be changed by application users, they can be stored in the
216  application configuration.
217 - _Dynamic permissions_ are defined on the application data. These permissions
218  will be set when the appropriate data is created. To allow application users
219  to change these permissions they are typically stored in the database.
220 
221 Different permission types require different ways of permission management,
222 particularly regarding storing permissions. To support this wCMF provides
223 several implementations of the
224 \link wcmf::lib::security::PermissionManager `PermissionManager`\endlink interface:
225 
226 - \link wcmf::lib::security::impl::StaticPermissionManager `StaticPermissionManager`\endlink
227  is used to retrieve permissions from the application configuration. The
228  permissions are stored in the `Authorization` configuration section like shown
229  in the following code:
230 
231 ~~~~~~~~~~~~~{.ini}
232 [Authorization]
233 ??login = +*
234 ??logout = +*
235 ??checkPermissions = +*
236 ??checkPermissionsOfUser = +administrators
237 app.src.model.wcmf.User??read = +administrators
238 app.src.model.wcmf.User??update = +administrators
239 app.src.model.wcmf.User??delete = +administrators
240 app.src.model.wcmf.User??create = +administrators
241 ~~~~~~~~~~~~~
242 
243 - \link wcmf::lib::security::impl::DefaultPermissionManager `DefaultPermissionManager`\endlink
244  handles permissions that are stored in the database. The entity type that actually
245  stores the permissions is required to have a _resource_, _context_, _action_
246  and _roles_ attribute and is defined in the application configuration. The
247  following lines are taken from the configuration of the \ref app "default application":
248 
249 ~~~~~~~~~~~~~{.ini}
250 [DefaultPermissionManager]
251 __class = wcmf\lib\security\impl\DefaultPermissionManager
252 permissionType = app.src.model.wcmf.Permission
253 ~~~~~~~~~~~~~
254 
255 - \link wcmf::lib::security::impl::ChainedPermissionManager `ChainedPermissionManager`\endlink
256  is used to combine different
257  \link wcmf::lib::security::PermissionManager `PermissionManager`\endlink instances.
258  When asked for authorization, it delegates the request to all it's managers, while
259  creation, modification and deletion of permissions is always handled by the
260  first contained manager. An example configuration of this manager is shown in
261  the code below:
262 
263 ~~~~~~~~~~~~~{.ini}
264 [PermissionManager]
265 __class = wcmf\lib\security\impl\ChainedPermissionManager
266 managers = {$defaultPermissionManager, $staticPermissionManager}
267 
268 [DefaultPermissionManager]
269 __class = wcmf\lib\security\impl\DefaultPermissionManager
270 permissionType = app.src.model.wcmf.Permission
271 
272 [StaticPermissionManager]
273 __class = wcmf\lib\security\impl\StaticPermissionManager
274 ~~~~~~~~~~~~~
275 
276 - \link wcmf::lib::security::impl::NullPermissionManager `NullPermissionManager`\endlink
277  acts like there is no permission manager and is merely used for testing.
278 
279 All implementations inherit from
280 \link wcmf::lib::security::impl::AbstractPermissionManager `AbstractPermissionManager`\endlink,
281 which already provides most of parts for handling authorization requests.
282 
283 #### Temporary permissions #### {#sec_perm_temp}
284 
285 There are situations, where a piece of code requires a certain permission in the
286 context of the current user, which is not possible to grant throughout the whole
287 application. For example, if a user wants to sign in to the application,
288 \link wcmf::lib::security::principal::PrincipalFactory `PrincipalFactory`\endlink
289 needs to provide a user instance although the anonymous user is not allowed
290 to read user instances. To accomplish this,
291 \link wcmf::lib::security::PermissionManager `PermissionManager`\endlink allows
292 to set a transient, temporary permission like in the following example:
293 
294 ~~~~~~~~~~~~~{.php}
295 $permissionManager = ObjectFactory::getInstance('permissionManager');
296 $persistenceFacade = ObjectFactory::getInstance('persistenceFacade');
297 $userType = 'app.src.model.wcmf.User';
298 
299 // set up a temporary permission to read the user instance for the given login
300 $permissionManager->addTempPermission($userType, '', PersistenceAction::READ);
301 
302 $user = $persistenceFacade->loadFirstObject($userType, BuildDepth::SINGLE,
303  array(
304  new Criteria($userType, 'login', '=', $login)
305  ), null);
306 
307 // remove the temporary permission
308 $permissionManager->removeTempPermission($userType, '', PersistenceAction::READ);
309 ~~~~~~~~~~~~~
310 
311 ### Checking permissions ### {#sec_perm_check}
312 
313 To test, if a user has the permission to access a resource in the requested way
314 the method
315 \link wcmf::lib::security::PermissionManager::authorize `PermissionManager::authorize`\endlink
316 is used. It returns a boolean value indicating whether the user is authorized
317 or not.
318 
319 The following code shows how to determine, if the current user is allowed to read
320 the given object:
321 
322 ~~~~~~~~~~~~~{.php}
323 $canRead = $permissionManager->authorize($object->getOID(), '', PersistenceAction::READ);
324 ~~~~~~~~~~~~~
325 
326 #### Default policies #### {#sec_perm_default_policies}
327 
328 Default policies answer the question, what happens if __no permission__ is defined
329 on a requested resource. These rules depend on the authentication status of the
330 current user and are defined in
331 \link wcmf::lib::security::impl::AbstractPermissionManager `AbstractPermissionManager`\endlink
332 as follows:
333 
334 - _Not authenticated_: Resource is _not accessible_
335 - _Authenticated_: Resource is _accessible_
336 
337 ## Input ## {#sec_input}
338 
339 Generally all external input sent to the application should be considered harmful.
340 
341 In PHP this input is stored in so called _Superglobals_, e.g. <em>$_GET</em>,
342 <em>$_POST</em>, <em>$_FILES</em>. To avoid using these global variables directly
343 in code, wCMF encapsulates them in the
344 \link wcmf::lib::presentation::Request `Request`\endlink instance and makes
345 them available through the
346 \link wcmf::lib::presentation::Request::getValue `Request::getValue`\endlink
347 method. Besides the variable name this method defines the following optional
348 parameters:
349 
350 - `$default` default value if the value is not contained in the request
351 - `$filter` [filter](http://php.net/manual/en/filter.filters.php) to be applied
352  to the value
353 - `$options` filter parameters if necessary
354 
355 The `$filter` and `$options` values are passed to the
356 [filter_var](http://php.net/manual/en/function.filter-var.php) function and the
357 result is returned by the method.
358 
359 The following code demonstrates the usage:
360 
361 ~~~~~~~~~~~~~{.php}
362 // validate an email value
363 $email = $request->getValue('email', '', FILTER_VALIDATE_EMAIL);
364 
365 // validate a date using a regular expression and
366 // return the current date on failure
367 $today = date('Y-m-d');
368 $options = array("options" => array("regexp" => "/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/"));
369 $date = $request->getValue('date', $today, FILTER_VALIDATE_REGEXP, $options);
370 ~~~~~~~~~~~~~
371 */