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