Newer
Older
Andreas Åkre Solberg
committed
Authentication Processing Filters in SimpleSAMLphp
==================================================
<!--
This file is written in Markdown syntax.
For more information about how to use the Markdown syntax, read here:
http://daringfireball.net/projects/markdown/syntax
-->
* Version: `$Id$`
Andreas Åkre Solberg
committed
In SimpleSAMLphp, there is an API where you can *do stuff* at the IdP after authentication is complete, and just before you are sent back to the SP. The same API is available on the SP, after you have received a successfull Authentication Response from the IdP and before you are sent back to the SP application.
Andreas Åkre Solberg
committed
Authentication processing filters postprocesses authentication information received from authentication sources. It is possible to use this for additional authentication checks, requesting the users consent before delivering attributes to the user, modifying the users attributes, and other things which should be performed before returning the user to the service provider he came from.
Andreas Åkre Solberg
committed
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
Examples of neat things to do using Authentication Processing Filters:
* Filter out a subset of available attributes that are sent to a SP.
* Mofify the name of attributes
* Generate new attributes that are composed of others. In example eduPersonTargetedID.
* Ask the user for consent, before the user is sent back to a service
* Implement basic Access Control on the IdP (not neccessarily a good idea), limiting access for some users to some SPs.
Be aware that Authentication Proccessing Filters do replace some of the preivous features in simpleSAMLphp, named:
* `attributemap`
* `attributealter`
* attribute filter
Later in this document, we will desribe in detail the alternative Authentication Proccessing Filters that will replicate these functionalities.
How to configure Auth Proc Filters
----------------------------------
*Auth Proc Filters* can be set globally, or to be specific for only one SP or one IdP. That means there is three locations where you can configure *Auth Proc Filters*:
* Globally in `config.php`
* On the SP: Specific for only one hosted SP in `saml20-sp-hosted` or `shib13-sp-hosted`
* On the SP: Specific for only one remote IdP in `saml20-idp-remote` or `shib13-idp-remote`
* On the IdP: Specific for only one hosted IdP in `saml20-idp-hosted` or `shib13-idp-hosted`
* On the IdP: Specific for only one remote SP in `saml20-sp-remote` or `shib13-sp-remote`
The configuration of *Auth Proc Filters* is a list of filters with priority as *index*. Here is an example of *Auth Proc Filters* configured in `config.php`:
'authproc.idp' => array(
10 => array(
'class' => 'core:AttributeMap',
'addurnprefix'
),
20 => 'core:TargetedID',
40 => 'core:AttributeRealm',
50 => 'core:AttributeLimit',
90 => array(
'class' => 'consent:Consent',
'store' => 'consent:Cookie',
'focus' => 'yes',
'checked' => TRUE
),
),
This configuration will execute *Auth Proc Filters* one by one, with the priority value in increasing order. When *Auth Proc Filters* is configured in multiple places, in example both globally, in the hosted IdP and remote SP metadata, then the list is interleaved sorted by priority.
The most important parameter of each item on the list is the *class* of the *Auth Proc Filter*. The syntax of the class is `modulename:classname`. As an example the class definition `core:AttributeLimit` will be expanded to look for the class `sspmod_core_Auth_Process_AttributeLimit`. The location of this class file *must* then be: `modules/core/lib/Auth/Process/AttributeLimit.php`.
You will see that a bunch of useful filters is included in the `core` module. In addition the `consent` module that is included in the simpleSAMLphp distribution implements a filter. Beyond that, you are encourage to create your own filters and share with the community. If you have created a cool *Auth Proc Filter* that do something useful, let us know, and we may share it from the [simpleSAMLphp web site][].
[simpleSAMLphp web site]: http://rnd.feide.no/simplesamlphp
When you know the class definition of a filter, and the priority, the simple way to configure the filter is:
20 => 'core:TargetedID',
This is analogue to:
20 => array(
'class' => 'core:TargetedID'
),
Some *Auth Proc Filters* have optional or required *parameters*. To send parameters to *Auth Proc Filters*, you need to choose the second of the two alernatives above. Here is an example of provided parameters to the consent module:
90 => array(
'class' => 'consent:Consent',
'store' => 'consent:Cookie',
'focus' => 'yes',
'checked' => TRUE
),
### Filters in `config.php`
Global *Auth Proc Filters* is configured in the `config.php` file. You will see that the config template already includes an example configuration.
There is two config parameters:
* `authproc.idp` and
* `authproc.sp`
The filters in `authproc.idp` will be executed at the IdP side regardless of which IdP and SP entity that is involved.
The filters in `authproc.sp` will be executed at the SP side regardless of which SP and IdP entity that is involved.
### Filters in metadata
Filters can be added both in `hosted` and `remote` metadata. Here is an example of a filter added in a metadata file:
'__DYNAMIC:1__' => array(
'host' => '__DEFAULT_',
'privatekey' => 'server.pem',
'certificate' => 'server.crt',
'auth' => 'feide',
'authproc' => array(
40 => 'core:AttributeRealm',
),
)
The example above is in `saml20-idp-hosted`.
Auth Proc Filters included in the simpleSAMLphp distribution
------------------------------------------------------------
Here is documentation on the *Auth Proc Filters* that is included in the simpleSAMLphp distribution.
### Adding attributes (`core:AttributeAdd`)
This filter allows you to add attributes to the attribute set being processed.
If the attribute already exists, the values added will be merged into a multi valued attribute. If you want to replace instead of merge attributes, you may add the `'%merge'` parameter.
Add a single valued attributes:
'authproc' => array(
50 => array(
'class' => 'core:AttributeAdd',
'source' => array('myidp')
),
),
Add a multi valued attribute:
'authproc' => array(
50 => array(
'class' => 'core:AttributeAdd',
'groups' => array('users', 'members')
),
),
Replace an existing attributes
'authproc' => array(
50 => array(
'class' => 'core:AttributeAdd',
'%replace',
'uid' => array('guest')
),
),
### Filtering attributes (`core:AttributeFilter`)
This *Auth Proc Filter* is backward compatible with the old way of filtering attributes. It operates in two modes:
1. List of attributes added as configuration to the filter
2. List of attributes specified in metadata (both SP and IdP) in the `attribute` parameter (as always)
#### Attribute list added as a parameter
Example configuration
'authproc' => array(
50 => array(
'class' => 'core:AttributeLimit',
'cn', 'mail'
),
),
#### Attribute list in metadata
If you do not add attributes as parameters to the filter, the filter will look up attributes in metadata.
'authproc' => array(
50 => 'core:AttributeLimit',
),
Here is an example of how attribute liste is defined in metadata:
'__DYNAMIC:1__' => array(
'host' => 'dev11.andreas.feide.no',
'privatekey' => 'server.pem',
'certificate' => 'server.crt',
'auth' => 'example-static',
'logouttype' => 'iframe',
'attributes' => array('cn', 'mail', 'sn', 'eduPersonTargetedID'),
),
Attribute filtering can be done both on the IdP and the SP side. On the SP side, attribute lists is read from *sp-hosted* and *idp-remote*. On IdP side, attribute lists is read from *idp-hosted* and *sp-remote*.
### Modifying attribute names (`core:AttributeMap`)
This *Auth Proc Filter* is backward compatible with the old way of modifying attribute names. It operates in two modes:
1. Attribute mapping table included as parameters to the filter.
2. The filter gets a name of an attributemap file as a parameter
#### Attribute maps embedded as parameters
Here is an example:
'authproc' => array(
50 => array(
'class' => 'core:AttributeMap',
'mail' => 'email',
'uid' => 'user'),
),
#### Attribute maps in separate files
Here is an example:
'authproc' => array(
50 => array(
'class' => 'core:AttributeMap',
'addurnprefix'
),
),
The example above will look for this file: `simpesamlphp/attributemap/addurnprefix.php`. As you see this file is already included as an example. Copy `addurnprefix.php` and add the new file in the same directory to add new attributemaps.
### Adding realm as an attribute (`core:AttributeRealm`)
No parameters required:
40 => 'core:AttributeRealm',
Alternatively, you can specify the attribute name that should be used instead of the default `realm`:
40 => array(
'class' => 'core:AttributeRealm',
'attributename' => 'homedomain',
)
This filter will look for the user ID on a format like `andreas@uninett.no`, and extract the part after the '`@`'-sign.
*What is the User ID?*
The User ID can be any attribute. The name of the User ID can be specified in the metadata as a `userid.attribute` parameter. Default value is `eduPersonPrincipalName`.
**Important**: You have to make sure that the User ID attribute is available at the time this filter is executed. You can do that by setting a lower priority number on this filter, than the filter that filters attributes.
### Automatically generated eduPersonTargetedID (`core:TargetedID`)
*eduPersonTargetedID* is an anonymous user attribute that is unique for each combination IdP and SP.
Example configuration:
'authproc' => array(
50 => 'core:TargetedID',
)
If you want to inject this new attribute with another name than the default `eduPersonTargetedID`:
'authproc' => array(
50 => array(
'class' => 'core:TargetedID',
'attributename' => 'anonymousID',
),
)
The automatic generation of `eduPersonTargetedID` requires that the User ID attribute is available.
*What is the User ID?*
The User ID can be any attribute. The name of the User ID can be specified in the metadata as a `userid.attribute` parameter. Default value is `eduPersonPrincipalName`.
**Important**: You have to make sure that the User ID attribute is available at the time this filter is executed. You can do that by setting a lower priority number on this filter, than the filter that filters attributes.
The formula used for automatically calculating this value is (pseudo code):
sha1(
'uidhashbase' + $secretSalt +
strlen($idpEntityid) + ':' + $idpEntityid +
strlen($spEntityid) + ':' + $spEntityid +
strlen($userID) + ':' + $userID +
$secretSalt
)
In example that could mean:
sha1( 'uidhashbaseq8d76f8ds75f68d7s24:https://idp.example.org
23:https://sp.example.org19:andreas@uninett.noq8d76f8ds75f68d7s' )
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
#### Internet2 compatible `eduPersontargetedID` ####
Internet2 uses an `<AttributeValue>` element with a `<NameID>` element to represent the `edupersonTargetedID`:
<saml2:AttributeValue>
<saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"
NameQualifier="https://idp.example.org/shibboleth"
SPNameQualifier="https://sp.example.org/shibboleth"
>1234567890</saml2:NameID>
</saml2:AttributeValue>
This format is documented in the [MACE-Dir SAML Attribute Profiles](http://middleware.internet2.edu/dir/docs/internet2-mace-dir-saml-attributes-200604.pdf) document.
To make simpleSAMLphp generate this kind of `eduPersonTargetedID`, you need to set the `nameId`-option to TRUE.
You also need to change the encoding of the `eduPersonTargetedID` attribute to `raw`.
Example:
$metadata['__DYNAMIC:1__'] = array(
'host' => '__DEFAULT__',
'auth' => 'example-static',
'authproc' => array(
60 => array(
'class' => 'core:TargetedID',
'nameId' => TRUE,
),
),
'attributeencodings' => array(
'eduPersonTargetedID' => 'raw',
),
);
Andreas Åkre Solberg
committed
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
### Adding a group attribute (`core:GenerateGroups`)
By default this filter will generate groups from the following set of attributes:
- `eduPersonAffiliation`
- `eduPersonOrgUnitDN`
- `eduPersonEntitlement`
This can be overridden by specifying the names of the attributes in the configuration.
It will attempt to determine a realm the user belongs to based on the User ID attribute, if it is present.
The groups this filter generates are on the form: `<attribute name>-<attributevalue>` and `<attributename>-<realm>-<attributevalue>`.
Note that this filter isn't a drop-in replacement for the groups attributealter function. The difference is that it uses the full attribute name, instead of shortening them to for example affiliation, and it escapes illegal characters in a style similar to urlencoding. It also generates groups both with and without a realm part. If no realm is determined, it will only generate attributes without a realm-part.
Example - generate from default set of attributes:
'authproc' => array(
50 => 'core:GenerateGroups',
),
Example - generate from only the `eduPersonAffilitation` attribute:
'authproc' => array(
50 => array(
'class' => 'core:GenerateGroups',
'eduPersonAffiliation'
),
),
Andreas Åkre Solberg
committed
### Adopting preferred language from and to attributes (`core:LanguageAdaptor`)
Andreas Åkre Solberg
committed
SimpleSAMLphp has built in language support, and stores the preferred language in a cookie.
Andreas Åkre Solberg
committed
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
Identity systems also often has a specific attribute that indicates what language is understood by the user. MACE defines an attribute with preferred language: `preferredLanguage`. [Read more about the preferredLanguage attribute defined by MACE](http://rnd.feide.no/node/1054).
The LanguageAdaptor brings these two concepts together. If executed early at the IdP it will check if the `preferredLanguage` attribute is among the users attributes, and if it is, simpleSAMLphp will use that language in the user interface. **Notice that** the login page itself is to early to be influenced by the user attributes, because the IdP does not know any user attributes before the user logs in. In contrast, the consent module will be presented in the correct language based on user attribute.
The LanguageAdaptor also works the other way around. If the user does not have the `preferredLanguage` attribute, the user interface for the user will be set to the default for the installation. If this language is not correct for the user, the user may click to switch language on the login page (or any other UI page in simpleSAMLphp). SimpleSAMLphp then stores the preferred language in a cookie. Now, the LanguageAdaptor will read the preferred language from the cookie and add a user attribute with the preferred language, that is sent to the service provider.
Example 1:
'authproc' => array(
30 => 'core:LanguageAdaptor',
),
Example 2: By default the filter will use the attribute name `preferredLanguage`. You can specify the name of the language attribute with an optional parameter:
'authproc' => array(
30 => array(
'class' => 'core:LanguageAdaptor',
'attributename' => 'lang',
),
),
You can use the LanguageAdaptor both at the SP and the IdP. It may even make sense to run the LanguageAdaptor twice at the IdP if there is any other processing filters executed that includes a UI.
Example 3:
'authproc.idp' => array(
20 => 'core:TargetedID',
30 => 'core:LanguageAdaptor',
40 => 'core:AttributeRealm',
50 => 'core:AttributeLimit',
90 => array(
'class' => 'consent:Consent',
'store' => 'consent:Cookie',
'focus' => 'yes',
'checked' => TRUE
),
99 => 'core:LanguageAdaptor',
),
Here you can see that the LanguageAdaptor runs with priority 30. At this point the filter will check attributes and set the simpleSAMLphp language cookie if the preferredLanguage attribute was provided. Later, with priority 99, the filter is ran again. This time the LanguageAdaptor will discover if the user have selected preferred language in the consent module, and if the user has selected language, and if the user does not already have a preferredLanguage attribute, the LanguageAdaptor will set the `preferredLanguage` attribute reflecting the user's language choice in the consent UI.
Andreas Åkre Solberg
committed
Writing your own Auth Proc Filter
---------------------------------
Andreas Åkre Solberg
committed
Look at the included *Auth Proc Filters* as examples. Copy the classes into your own module and start playing around.
Andreas Åkre Solberg
committed
Andreas Åkre Solberg
committed
Authentication processing filters are created by creating a class under `Auth/Process/` in a module. This class is expected to subclass `SimpleSAML_Auth_ProcessingFilter`. A filter must implement at lease one function - the `process(&$request)`-function. This function can access the `$request`-array add, delete and modify attributes, and can also do more advanced processing based on the SP/IdP metadata (which is also included in the `$request`-array). When this function returns, it is assumed that the filter has finished processing.
If a filter for some reason needs to redirect the user, for example to show a web page, it should save the current request. Upon completion it should retrieve the request, update it with the changes it is going to make, and call `SimpleSAML_Auth_ProcessingChain::resumeProcessing`. This function will continue processing the next configured filter.
Andreas Åkre Solberg
committed
Andreas Åkre Solberg
committed
Requirements for authentication processing filters:
- Must be derived from the `SimpleSAML_Auth_ProcessingFilter`-class.
- If a constructor is implemented, it must first call the parent constructor, passing along all parameters, before accessing any of the parameters. In general, only the $config parameter should be accessed.
- The `process(&$state)`-function must be implemented. If this function completes, it is assumed that processing is completed, and that the $request array has been updated.
- If the `process`-function does not return, it must at a later time call `SimpleSAML_Auth_ProcessingChain::resumeProcessing` with the new request state. The request state must be an update of the array passed to the `process`-function.
- No pages may be shown to the user from the `process`-function. Instead, the request state should be saved, and the user should be redirected to a new page. This must be done to prevent unpredictable events if the user for example reloads the page.
- No state information should be stored in the filter object. It must instead be stored in the request state array. Any changes to variables in the filter object may be lost.
- The filter object must be serializable. It may be serialized between being constructed and the call to the `process`-function. This means that, for example, no database connections should be created in the constructor and later used in the `process`-function.
Don't hestitate to ask on the simpleSAMLphp mailinglist if you have problems or questions, or want to share your *Auth Proc Filter* with others.