ILIAS  release_7 Revision v7.30-3-g800a261c036
All Data Structures Namespaces Files Functions Variables Modules Pages
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
18 
19 chdir(dirname(__FILE__));
20 
22 $cookie_path = dirname($_SERVER['PHP_SELF']);
23 
24 $i = 0;
25 while (!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 
33 if (!file_exists(getcwd() . '/ilias.ini.php')) {
34  die('Please ensure ILIAS is installed!');
35 }
36 
37 $cookie_path .= (!preg_match("/[\/|\\\\]$/", $cookie_path)) ? "/" : "";
38 
39 if (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 }
47 define('IL_COOKIE_PATH', $cookie_path);
48 
49 require_once 'Services/Context/classes/class.ilContext.php';
51 
52 require_once 'Services/Init/classes/class.ilInitialisation.php';
54 
55 $iliasHttpPath = ILIAS_HTTP_PATH;
56 
57 require_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
63 if (!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();
69 if ($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);
77 if ($source === null) {
78  throw new AuthSource($sourceId, 'Could not find authentication source.');
79 }
80 
81 if (!($source instanceof SP)) {
82  throw new AuthSource(
83  $sourceId,
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 
104 foreach ($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 
122 if ($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 
128 $index = 0;
129 $eps = [];
131 foreach ($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_');
189 if ($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);
205 if ($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);
219 if ($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 
233 if ($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);
263 if ($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 
277 if ($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');
286 if ($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
294 if (count($keys) === 1) {
295  $metaArray20['certData'] = $keys[0]['X509Certificate'];
296 } elseif (count($keys) > 1) {
297  $metaArray20['keys'] = $keys;
298 }
299 
300 // add EntityAttributes extension
301 if ($spconfig->hasValue('EntityAttributes')) {
302  $metaArray20['EntityAttributes'] = $spconfig->getArray('EntityAttributes');
303 }
304 
305 // add UIInfo extension
306 if ($spconfig->hasValue('UIInfo')) {
307  $metaArray20['UIInfo'] = $spconfig->getArray('UIInfo');
308 }
309 
310 // add RegistrationInfo extension
311 if ($spconfig->hasValue('RegistrationInfo')) {
312  $metaArray20['RegistrationInfo'] = $spconfig->getArray('RegistrationInfo');
313 }
314 
315 // add signature options
316 if ($spconfig->hasValue('WantAssertionsSigned')) {
317  $metaArray20['saml20.sign.assertion'] = $spconfig->getBoolean('WantAssertionsSigned');
318 }
319 if ($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';
326 $metaArray20['entityid'] = $entityId;
327 
328 $metaBuilder = new SAMLBuilder($entityId);
330 $metaBuilder->addOrganizationInfo($metaArray20);
331 
332 $xml = $metaBuilder->getEntityDescriptorText();
333 
334 unset($metaArray20['UIInfo']);
335 unset($metaArray20['metadata-set']);
336 unset($metaArray20['entityid']);
337 
338 // sanitize the attributes array to remove friendly names
339 if (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 
346 if (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 }
$ilias_main_directory
Definition: metadata.php:21
$store
Definition: metadata.php:90
$attributes
Definition: metadata.php:231
$slob
Definition: metadata.php:99
$_GET["client_id"]
$metaArray20
Definition: metadata.php:92
if(!array_key_exists('PATH_INFO', $_SERVER)) $config
Definition: metadata.php:68
if($name !==null &&!empty($attributes)) $orgName
Definition: metadata.php:262
$slol
Definition: metadata.php:101
static getASCIIFilename($a_filename)
convert utf8 to ascii filename
$index
Definition: metadata.php:128
$ascii_filename
Definition: metadata.php:361
foreach($slob as $binding) $assertionsconsumerservicesdefault
Definition: metadata.php:115
$auth
Definition: metadata.php:59
if($format !==null) $name
Definition: metadata.php:230
$cookie_path
Definition: metadata.php:22
static initILIAS()
ilias initialisation
const CONTEXT_SAML
$keys
Definition: metadata.php:187
$iliasHttpPath
Definition: metadata.php:55
$_SERVER['HTTP_HOST']
Definition: raiseError.php:10
$spconfig
Definition: metadata.php:89
const CLIENT_ID
Definition: constants.php:39
global $DIC
Definition: goto.php:24
$slosvcdefault
Definition: metadata.php:94
$format
Definition: metadata.php:218
$metaBuilder
Definition: metadata.php:328
$xml
Definition: metadata.php:332
if($spconfig->getString('ProtocolBinding', '')=='urn:oasis:names:tc:SAML:2.0:profiles:holder-of-key:SSO:browser') $assertionsconsumerservices
Definition: metadata.php:126
if($orgName !==null) if($spconfig->hasValue('contacts')) $email
Definition: metadata.php:285
static init($a_type)
Init context by type.
$supported_protocols
Definition: metadata.php:130
$certInfo
Definition: metadata.php:188
if($source===null) if(!($source instanceof SP)) $entityId
Definition: metadata.php:88
if($config->getBoolean('admin.protectmetadata', false)) $sourceId
Definition: metadata.php:74
Class ilSamlAuthFactory.
$eps
Definition: metadata.php:129
$_COOKIE[session_name()]
Definition: xapitoken.php:37
$source
Definition: metadata.php:76
$factory
Definition: metadata.php:58
$i
Definition: metadata.php:24