Toggle navigation
wCMF 4.0
Guides
Getting started
Architecture
Model
Persistence
Presentation
Configuration
Security
I18n & l10n
Tests
API
Code
Support
wcmf_older
wcmf
docs
api-src
framework_description
en
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
*/