ILIAS  release_6 Revision v6.24-5-g0c8bfefb3b8
metadata.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 1998-2017 ILIAS open source, Extended GPL, see docs/LICENSE */
3// ilias-patch: begin
4use SAML2\Constants;
5use SimpleSAML\Auth\Source;
6use SimpleSAML\Configuration;
7use SimpleSAML\Error\AuthSource;
8use SimpleSAML\Locale\Translate;
9use SimpleSAML\Metadata\SAMLBuilder;
10use SimpleSAML\Metadata\Signer;
11use SimpleSAML\Module\saml\Auth\Source\SP;
12use SimpleSAML\Store;
13use SimpleSAML\Store\SQL;
14use SimpleSAML\Utils\Auth;
15use SimpleSAML\Utils\Config\Metadata;
16use SimpleSAML\Utils\Crypto;
17use SimpleSAML\XHTML\Template;
18
19chdir(dirname(__FILE__));
20
22$cookie_path = dirname($_SERVER['PHP_SELF']);
23
24$i = 0;
25while (!file_exists($ilias_main_directory . 'ilias.ini.php') && $i < 20) {
26 $ilias_main_directory .= '../';
27 ++$i;
28
29 $cookie_path = dirname($cookie_path);
30}
32
33if (!file_exists(getcwd() . '/ilias.ini.php')) {
34 die('Please ensure ILIAS is installed!');
35}
36
37$cookie_path .= (!preg_match("/[\/|\\\\]$/", $cookie_path)) ? "/" : "";
38
39if (isset($_GET["client_id"])) {
40 if ($cookie_path == "\\") {
41 $cookie_path = '/';
42 }
43
44 setcookie('ilClientId', $_GET['client_id'], 0, $cookie_path, '');
45 $_COOKIE['ilClientId'] = $_GET['client_id'];
46}
47define('IL_COOKIE_PATH', $cookie_path);
48
49require_once 'Services/Context/classes/class.ilContext.php';
51
52require_once 'Services/Init/classes/class.ilInitialisation.php';
54
56
57require_once 'Services/Saml/classes/class.ilSamlAuthFactory.php';
59$auth = $factory->auth();
60
61// The source code below is copied from the SimpleSAMLphp library and modified regarding the HTTP path
62// ilias-patch: end
63if (!array_key_exists('PATH_INFO', $_SERVER)) {
64 global $DIC;
65 $DIC->logger()->root()->warning('Missing "PATH_INFO" variable. This could be a false positive log entry, but you have to ensure a valid "PATH_INFO" setting for your HTTP server.');
66}
67
68$config = Configuration::getInstance();
69if ($config->getBoolean('admin.protectmetadata', false)) {
70 Auth::requireAdmin();
71}
72// ilias-patch: begin
73//$sourceId = substr($_SERVER['PATH_INFO'], 1);
74$sourceId = $auth->getAuthId();
75// ilias-patch: end
76$source = Source::getById($sourceId);
77if ($source === null) {
78 throw new AuthSource($sourceId, 'Could not find authentication source.');
79}
80
81if (!($source instanceof SP)) {
82 throw new AuthSource(
84 'The authentication source is not a SAML Service Provider.'
85 );
86}
87
88$entityId = $source->getEntityId();
89$spconfig = $source->getMetadata();
90$store = Store::getInstance();
91
93
95 Constants::BINDING_HTTP_REDIRECT,
96 Constants::BINDING_SOAP,
97];
98
99$slob = $spconfig->getArray('SingleLogoutServiceBinding', $slosvcdefault);
100// ilias-patch: begin
101$slol = $iliasHttpPath . '/saml2-logout.php/' . $sourceId . '/' . CLIENT_ID;
102// ilias-patch: end
103
104foreach ($slob as $binding) {
105 if ($binding == Constants::BINDING_SOAP && !($store instanceof SQL)) {
106 // we cannot properly support SOAP logout
107 continue;
108 }
109 $metaArray20['SingleLogoutService'][] = [
110 'Binding' => $binding,
111 'Location' => $slol,
112 ];
113}
114
116 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST',
117 'urn:oasis:names:tc:SAML:1.0:profiles:browser-post',
118 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact',
119 'urn:oasis:names:tc:SAML:1.0:profiles:artifact-01',
120];
121
122if ($spconfig->getString('ProtocolBinding', '') == 'urn:oasis:names:tc:SAML:2.0:profiles:holder-of-key:SSO:browser') {
123 $assertionsconsumerservicesdefault[] = 'urn:oasis:names:tc:SAML:2.0:profiles:holder-of-key:SSO:browser';
124}
125
127
129$eps = [];
131foreach ($assertionsconsumerservices as $services) {
132 $acsArray = ['index' => $index];
133 switch ($services) {
134 case 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST':
135 $acsArray['Binding'] = Constants::BINDING_HTTP_POST;
136 // ilias-patch: begin
137 $acsArray['Location'] = $iliasHttpPath . "/saml2-acs.php/{$sourceId}/" . CLIENT_ID;
138 // ilias-patch: end
139 if (!in_array(Constants::NS_SAMLP, $supported_protocols, true)) {
140 $supported_protocols[] = Constants::NS_SAMLP;
141 }
142 break;
143 case 'urn:oasis:names:tc:SAML:1.0:profiles:browser-post':
144 $acsArray['Binding'] = 'urn:oasis:names:tc:SAML:1.0:profiles:browser-post';
145 // ilias-patch: begin
146 $acsArray['Location'] = $iliasHttpPath . "/saml1-acs.php/{$sourceId}/" . CLIENT_ID;
147 // ilias-patch: end
148 if (!in_array('urn:oasis:names:tc:SAML:1.1:protocol', $supported_protocols, true)) {
149 $supported_protocols[] = 'urn:oasis:names:tc:SAML:1.1:protocol';
150 }
151 break;
152 case 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact':
153 $acsArray['Binding'] = 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact';
154 // ilias-patch: begin
155 $acsArray['Location'] = $iliasHttpPath . "/saml2-acs.php/{$sourceId}/" . CLIENT_ID;
156 // ilias-patch: end
157 if (!in_array(Constants::NS_SAMLP, $supported_protocols, true)) {
158 $supported_protocols[] = Constants::NS_SAMLP;
159 }
160 break;
161 case 'urn:oasis:names:tc:SAML:1.0:profiles:artifact-01':
162 $acsArray['Binding'] = 'urn:oasis:names:tc:SAML:1.0:profiles:artifact-01';
163 // ilias-patch: begin
164 $acsArray['Location'] = $iliasHttpPath . "/saml1-acs.php/{$sourceId}/artifact/" . CLIENT_ID;
165 // ilias-patch: end
166 if (!in_array('urn:oasis:names:tc:SAML:1.1:protocol', $supported_protocols, true)) {
167 $supported_protocols[] = 'urn:oasis:names:tc:SAML:1.1:protocol';
168 }
169 break;
170 case 'urn:oasis:names:tc:SAML:2.0:profiles:holder-of-key:SSO:browser':
171 $acsArray['Binding'] = 'urn:oasis:names:tc:SAML:2.0:profiles:holder-of-key:SSO:browser';
172 // ilias-patch: begin
173 $acsArray['Location'] = $iliasHttpPath . "/saml2-acs.php/{$sourceId}/" . CLIENT_ID;
174 // ilias-patch: end
175 $acsArray['hoksso:ProtocolBinding'] = Constants::BINDING_HTTP_REDIRECT;
176 if (!in_array(Constants::NS_SAMLP, $supported_protocols, true)) {
177 $supported_protocols[] = Constants::NS_SAMLP;
178 }
179 break;
180 }
181 $eps[] = $acsArray;
182 $index++;
183}
184
185$metaArray20['AssertionConsumerService'] = $eps;
186
187$keys = [];
188$certInfo = Crypto::loadPublicKey($spconfig, false, 'new_');
189if ($certInfo !== null && array_key_exists('certData', $certInfo)) {
190 $hasNewCert = true;
191
192 $certData = $certInfo['certData'];
193
194 $keys[] = [
195 'type' => 'X509Certificate',
196 'signing' => true,
197 'encryption' => true,
198 'X509Certificate' => $certInfo['certData'],
199 ];
200} else {
201 $hasNewCert = false;
202}
203
204$certInfo = Crypto::loadPublicKey($spconfig);
205if ($certInfo !== null && array_key_exists('certData', $certInfo)) {
206 $certData = $certInfo['certData'];
207
208 $keys[] = [
209 'type' => 'X509Certificate',
210 'signing' => true,
211 'encryption' => ($hasNewCert ? false : true),
212 'X509Certificate' => $certInfo['certData'],
213 ];
214} else {
215 $certData = null;
216}
217
218$format = $spconfig->getValue('NameIDPolicy', null);
219if ($format !== null) {
220 if (is_array($format)) {
221 $metaArray20['NameIDFormat'] = Configuration::loadFromArray($format)->getString(
222 'Format',
223 Constants::NAMEID_TRANSIENT
224 );
225 } elseif (is_string($format)) {
226 $metaArray20['NameIDFormat'] = $format;
227 }
228}
229
230$name = $spconfig->getLocalizedString('name', null);
231$attributes = $spconfig->getArray('attributes', []);
232
233if ($name !== null && !empty($attributes)) {
234 $metaArray20['name'] = $name;
235 $metaArray20['attributes'] = $attributes;
236 $metaArray20['attributes.required'] = $spconfig->getArray('attributes.required', []);
237
238 if (empty($metaArray20['attributes.required'])) {
239 unset($metaArray20['attributes.required']);
240 }
241
242 $description = $spconfig->getArray('description', null);
243 if ($description !== null) {
244 $metaArray20['description'] = $description;
245 }
246
247 $nameFormat = $spconfig->getString('attributes.NameFormat', null);
248 if ($nameFormat !== null) {
249 $metaArray20['attributes.NameFormat'] = $nameFormat;
250 }
251
252 if ($spconfig->hasValue('attributes.index')) {
253 $metaArray20['attributes.index'] = $spconfig->getInteger('attributes.index', 0);
254 }
255
256 if ($spconfig->hasValue('attributes.isDefault')) {
257 $metaArray20['attributes.isDefault'] = $spconfig->getBoolean('attributes.isDefault', false);
258 }
259}
260
261// add organization info
262$orgName = $spconfig->getLocalizedString('OrganizationName', null);
263if ($orgName !== null) {
264 $metaArray20['OrganizationName'] = $orgName;
265
266 $metaArray20['OrganizationDisplayName'] = $spconfig->getLocalizedString('OrganizationDisplayName', null);
267 if ($metaArray20['OrganizationDisplayName'] === null) {
268 $metaArray20['OrganizationDisplayName'] = $orgName;
269 }
270
271 $metaArray20['OrganizationURL'] = $spconfig->getLocalizedString('OrganizationURL', null);
272 if ($metaArray20['OrganizationURL'] === null) {
273 throw new \SimpleSAML\Error\Exception('If OrganizationName is set, OrganizationURL must also be set.');
274 }
275}
276
277if ($spconfig->hasValue('contacts')) {
278 $contacts = $spconfig->getArray('contacts');
279 foreach ($contacts as $contact) {
280 $metaArray20['contacts'][] = Metadata::getContact($contact);
281 }
282}
283
284// add technical contact
285$email = $config->getString('technicalcontact_email', 'na@example.org');
286if ($email && $email !== 'na@example.org') {
287 $techcontact['emailAddress'] = $email;
288 $techcontact['name'] = $config->getString('technicalcontact_name', null);
289 $techcontact['contactType'] = 'technical';
290 $metaArray20['contacts'][] = Metadata::getContact($techcontact);
291}
292
293// add certificate
294if (count($keys) === 1) {
295 $metaArray20['certData'] = $keys[0]['X509Certificate'];
296} elseif (count($keys) > 1) {
297 $metaArray20['keys'] = $keys;
298}
299
300// add EntityAttributes extension
301if ($spconfig->hasValue('EntityAttributes')) {
302 $metaArray20['EntityAttributes'] = $spconfig->getArray('EntityAttributes');
303}
304
305// add UIInfo extension
306if ($spconfig->hasValue('UIInfo')) {
307 $metaArray20['UIInfo'] = $spconfig->getArray('UIInfo');
308}
309
310// add RegistrationInfo extension
311if ($spconfig->hasValue('RegistrationInfo')) {
312 $metaArray20['RegistrationInfo'] = $spconfig->getArray('RegistrationInfo');
313}
314
315// add signature options
316if ($spconfig->hasValue('WantAssertionsSigned')) {
317 $metaArray20['saml20.sign.assertion'] = $spconfig->getBoolean('WantAssertionsSigned');
318}
319if ($spconfig->hasValue('redirect.sign')) {
320 $metaArray20['redirect.validate'] = $spconfig->getBoolean('redirect.sign');
321} elseif ($spconfig->hasValue('sign.authnrequest')) {
322 $metaArray20['validate.authnrequest'] = $spconfig->getBoolean('sign.authnrequest');
323}
324
325$metaArray20['metadata-set'] = 'saml20-sp-remote';
327
328$metaBuilder = new SAMLBuilder($entityId);
330$metaBuilder->addOrganizationInfo($metaArray20);
331
332$xml = $metaBuilder->getEntityDescriptorText();
333
334unset($metaArray20['UIInfo']);
335unset($metaArray20['metadata-set']);
336unset($metaArray20['entityid']);
337
338// sanitize the attributes array to remove friendly names
339if (isset($metaArray20['attributes']) && is_array($metaArray20['attributes'])) {
340 $metaArray20['attributes'] = array_values($metaArray20['attributes']);
341}
342
343// sign the metadata if enabled
344$xml = Signer::sign($xml, $spconfig->toArray(), 'SAML 2 SP');
345
346if (array_key_exists('output', $_REQUEST) && $_REQUEST['output'] == 'xhtml') {
347 $t = new Template($config, 'metadata.php', 'admin');
348
349 $t->data['clipboard.js'] = true;
350 $t->data['header'] = 'saml20-sp'; // TODO: Replace with headerString in 2.0
351 $t->data['headerString'] = Translate::noop('metadata_saml20-sp');
352 $t->data['metadata'] = htmlspecialchars($xml);
353 $t->data['metadataflat'] = '$metadata[' . var_export($entityId, true) . '] = ' . var_export($metaArray20, true) . ';';
354 // ilias-patch: begin
355 $t->data['metaurl'] = $iliasHttpPath . "/metadata.php{$sourceId}/" . CLIENT_ID;
356 // ilias-patch: end
357 $t->show();
358} else {
359 header('Content-Type: application/samlmetadata+xml');
360 // ilias-patch: begin
362 header("Content-Disposition:attachment; filename=\"" . $ascii_filename . "\"");
363 // ilias-patch: end
364 echo($xml);
365}
$_GET["client_id"]
An exception for terminatinating execution or to throw for unit testing.
static init($a_type)
Init context by type.
const CONTEXT_SAML
static initILIAS()
ilias initialisation
Class ilSamlAuthFactory.
static getASCIIFilename($a_filename)
convert utf8 to ascii filename
$factory
Definition: metadata.php:58
if($name !==null &&!empty($attributes)) $orgName
Definition: metadata.php:262
if($format !==null) $name
Definition: metadata.php:230
$format
Definition: metadata.php:218
$cookie_path
Definition: metadata.php:22
$auth
Definition: metadata.php:59
$index
Definition: metadata.php:128
$spconfig
Definition: metadata.php:89
$ascii_filename
Definition: metadata.php:361
$slol
Definition: metadata.php:101
$metaBuilder
Definition: metadata.php:328
$supported_protocols
Definition: metadata.php:130
if(!array_key_exists('PATH_INFO', $_SERVER)) $config
Definition: metadata.php:68
$metaArray20
Definition: metadata.php:92
foreach($slob as $binding) $assertionsconsumerservicesdefault
Definition: metadata.php:115
$store
Definition: metadata.php:90
$i
Definition: metadata.php:24
$slob
Definition: metadata.php:99
if( $orgName !==null) if($spconfig->hasValue('contacts')) $email
Definition: metadata.php:285
if($spconfig->getString('ProtocolBinding', '')=='urn:oasis:names:tc:SAML:2.0:profiles:holder-of-key:SSO:browser') $assertionsconsumerservices
Definition: metadata.php:126
$eps
Definition: metadata.php:129
$source
Definition: metadata.php:76
if($config->getBoolean('admin.protectmetadata', false)) $sourceId
Definition: metadata.php:74
if( $source===null) if(!($source instanceof SP)) $entityId
Definition: metadata.php:88
$iliasHttpPath
Definition: metadata.php:55
$slosvcdefault
Definition: metadata.php:94
$ilias_main_directory
Definition: metadata.php:21
$attributes
Definition: metadata.php:231
$certInfo
Definition: metadata.php:188
$keys
Definition: metadata.php:187
$xml
Definition: metadata.php:332
$_SERVER['HTTP_HOST']
Definition: raiseError.php:10
$DIC
Definition: xapitoken.php:46
$_COOKIE[session_name()]
Definition: xapitoken.php:39