ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
Message.php
Go to the documentation of this file.
1<?php
2
3namespace SAML2;
4
8
18abstract class Message implements SignedElement
19{
25 protected $extensions;
26
34 private $tagName;
35
41 private $id;
42
49
55 private $destination;
56
62 private $consent = Constants::CONSENT_UNSPECIFIED;
63
69 private $issuer;
70
76 private $relayState;
77
86 protected $document;
87
96
100 protected $messageContainedSignatureUponConstruction = false;
101
108
114 private $validators;
115
120
136 protected function __construct($tagName, \DOMElement $xml = null)
137 {
138 assert(is_string($tagName));
139 $this->tagName = $tagName;
140
141 $this->id = Utils::getContainer()->generateId();
142 $this->issueInstant = Temporal::getTime();
143 $this->certificates = array();
144 $this->validators = array();
145
146 if ($xml === null) {
147 return;
148 }
149
150 if (!$xml->hasAttribute('ID')) {
151 throw new \Exception('Missing ID attribute on SAML message.');
152 }
153 $this->id = $xml->getAttribute('ID');
154
155 if ($xml->getAttribute('Version') !== '2.0') {
156 /* Currently a very strict check. */
157 throw new \Exception('Unsupported version: '.$xml->getAttribute('Version'));
158 }
159
160 $this->issueInstant = Utils::xsDateTimeToTimestamp($xml->getAttribute('IssueInstant'));
161
162 if ($xml->hasAttribute('Destination')) {
163 $this->destination = $xml->getAttribute('Destination');
164 }
165
166 if ($xml->hasAttribute('Consent')) {
167 $this->consent = $xml->getAttribute('Consent');
168 }
169
170 $issuer = Utils::xpQuery($xml, './saml_assertion:Issuer');
171 if (!empty($issuer)) {
172 $this->issuer = new XML\saml\Issuer($issuer[0]);
173 if ($this->issuer->Format === Constants::NAMEID_ENTITY) {
174 $this->issuer = $this->issuer->value;
175 }
176 }
177
178 $this->validateSignature($xml);
179
180 $this->extensions = Extensions::getList($xml);
181 }
182
183
193 private function validateSignature(\DOMElement $xml)
194 {
195 try {
197 $signatureMethod = Utils::xpQuery($xml, './ds:Signature/ds:SignedInfo/ds:SignatureMethod/@Algorithm');
198
199 $sig = Utils::validateElement($xml);
200
201 if ($sig !== false) {
202 $this->messageContainedSignatureUponConstruction = true;
203 $this->certificates = $sig['Certificates'];
204 $this->validators[] = array(
205 'Function' => array('\SAML2\Utils', 'validateSignature'),
206 'Data' => $sig,
207 );
208 $this->signatureMethod = $signatureMethod[0]->value;
209 }
210 } catch (\Exception $e) {
211 // ignore signature validation errors
212 }
213 }
214
215
225 public function addValidator($function, $data)
226 {
227 assert(is_callable($function));
228
229 $this->validators[] = array(
230 'Function' => $function,
231 'Data' => $data,
232 );
233 }
234
248 public function validate(XMLSecurityKey $key)
249 {
250 if (count($this->validators) === 0) {
251 return false;
252 }
253
254 $exceptions = array();
255
256 foreach ($this->validators as $validator) {
257 $function = $validator['Function'];
258 $data = $validator['Data'];
259
260 try {
261 call_user_func($function, $data, $key);
262 /* We were able to validate the message with this validator. */
263
264 return true;
265 } catch (\Exception $e) {
266 $exceptions[] = $e;
267 }
268 }
269
270 /* No validators were able to validate the message. */
271 throw $exceptions[0];
272 }
273
279 public function getId()
280 {
281 return $this->id;
282 }
283
289 public function setId($id)
290 {
291 assert(is_string($id));
292
293 $this->id = $id;
294 }
295
301 public function getIssueInstant()
302 {
303 return $this->issueInstant;
304 }
305
311 public function setIssueInstant($issueInstant)
312 {
313 assert(is_int($issueInstant));
314
315 $this->issueInstant = $issueInstant;
316 }
317
323 public function getDestination()
324 {
325 return $this->destination;
326 }
327
334 {
335 assert(is_string($destination) || is_null($destination));
336
337 $this->destination = $destination;
338 }
339
349 public function setConsent($consent)
350 {
351 assert(is_string($consent));
352
353 $this->consent = $consent;
354 }
355
365 public function getConsent()
366 {
367 return $this->consent;
368 }
369
375 public function getIssuer()
376 {
377 if (is_string($this->issuer) || $this->issuer instanceof XML\saml\Issuer) {
378 return $this->issuer;
379 }
380
381 return null;
382 }
383
389 public function setIssuer($issuer)
390 {
391 assert(is_string($issuer) || $issuer instanceof XML\saml\Issuer || is_null($issuer));
392
393 $this->issuer = $issuer;
394 }
395
402 {
403 return $this->messageContainedSignatureUponConstruction;
404 }
405
411 public function getRelayState()
412 {
413 return $this->relayState;
414 }
415
421 public function setRelayState($relayState)
422 {
423 assert(is_string($relayState) || is_null($relayState));
424
425 $this->relayState = $relayState;
426 }
427
435 public function toUnsignedXML()
436 {
437 $this->document = DOMDocumentFactory::create();
438
439 $root = $this->document->createElementNS(Constants::NS_SAMLP, 'samlp:'.$this->tagName);
440 $this->document->appendChild($root);
441
442 /* Ugly hack to add another namespace declaration to the root element. */
443 $root->setAttributeNS(Constants::NS_SAML, 'saml:tmp', 'tmp');
444 $root->removeAttributeNS(Constants::NS_SAML, 'tmp');
445
446 $root->setAttribute('ID', $this->id);
447 $root->setAttribute('Version', '2.0');
448 $root->setAttribute('IssueInstant', gmdate('Y-m-d\TH:i:s\Z', $this->issueInstant));
449
450 if ($this->destination !== null) {
451 $root->setAttribute('Destination', $this->destination);
452 }
453 if ($this->consent !== null && $this->consent !== Constants::CONSENT_UNSPECIFIED) {
454 $root->setAttribute('Consent', $this->consent);
455 }
456
457 if ($this->issuer !== null) {
458 if (is_string($this->issuer)) {
459 Utils::addString($root, Constants::NS_SAML, 'saml:Issuer', $this->issuer);
460 } elseif ($this->issuer instanceof XML\saml\Issuer) {
461 $this->issuer->toXML($root);
462 }
463 }
464
465 if (!empty($this->extensions)) {
466 Extensions::addList($root, $this->extensions);
467 }
468
469 return $root;
470 }
471
472
481 public function toSignedXML()
482 {
483 $root = $this->toUnsignedXML();
484
485 if ($this->signatureKey === null) {
486 /* We don't have a key to sign it with. */
487
488 return $root;
489 }
490
491 /* Find the position we should insert the signature node at. */
492 if ($this->issuer !== null) {
493 /*
494 * We have an issuer node. The signature node should come
495 * after the issuer node.
496 */
497 $issuerNode = $root->firstChild;
498 $insertBefore = $issuerNode->nextSibling;
499 } else {
500 /* No issuer node - the signature element should be the first element. */
501 $insertBefore = $root->firstChild;
502 }
503
504 Utils::insertSignature($this->signatureKey, $this->certificates, $root, $insertBefore);
505
506 return $root;
507 }
508
514 public function getSignatureKey()
515 {
516 return $this->signatureKey;
517 }
518
526 public function setSignatureKey(XMLSecurityKey $signatureKey = null)
527 {
528 $this->signatureKey = $signatureKey;
529 }
530
538 public function setCertificates(array $certificates)
539 {
540 $this->certificates = $certificates;
541 }
542
548 public function getCertificates()
549 {
550 return $this->certificates;
551 }
552
562 public static function fromXML(\DOMElement $xml)
563 {
564 if ($xml->namespaceURI !== Constants::NS_SAMLP) {
565 throw new \Exception('Unknown namespace of SAML message: '.var_export($xml->namespaceURI, true));
566 }
567
568 switch ($xml->localName) {
569 case 'AttributeQuery':
570 return new AttributeQuery($xml);
571 case 'AuthnRequest':
572 return new AuthnRequest($xml);
573 case 'LogoutResponse':
574 return new LogoutResponse($xml);
575 case 'LogoutRequest':
576 return new LogoutRequest($xml);
577 case 'Response':
578 return new Response($xml);
579 case 'ArtifactResponse':
580 return new ArtifactResponse($xml);
581 case 'ArtifactResolve':
582 return new ArtifactResolve($xml);
583 default:
584 throw new \Exception('Unknown SAML message: '.var_export($xml->localName, true));
585 }
586 }
587
593 public function getExtensions()
594 {
595 return $this->extensions;
596 }
597
603 public function setExtensions($extensions)
604 {
605 assert(is_array($extensions) || is_null($extensions));
606
607 $this->extensions = $extensions;
608 }
609
613 public function getSignatureMethod()
614 {
615 return $this->signatureMethod;
616 }
617}
catch(Exception $e) if(!($request instanceof \SAML2\ArtifactResolve)) $issuer
getTime()
Definition: MetaLoader.php:479
$exceptions
Definition: Utf8Test.php:67
$function
Definition: cas.php:28
An exception for terminatinating execution or to throw for unit testing.
Base class for all SAML 2 messages.
Definition: Message.php:19
toUnsignedXML()
Convert this message to an unsigned XML document.
Definition: Message.php:435
getRelayState()
Retrieve the RelayState associated with this message.
Definition: Message.php:411
getSignatureMethod()
Definition: Message.php:613
setRelayState($relayState)
Set the RelayState associated with this message.
Definition: Message.php:421
getSignatureKey()
Retrieve the private key we should use to sign the message.
Definition: Message.php:514
setCertificates(array $certificates)
Set the certificates that should be included in the message.
Definition: Message.php:538
isMessageConstructedWithSignature()
Query whether or not the message contained a signature at the root level when the object was construc...
Definition: Message.php:401
getExtensions()
Retrieve the Extensions.
Definition: Message.php:593
__construct($tagName, \DOMElement $xml=null)
Initialize a message.
Definition: Message.php:136
validate(XMLSecurityKey $key)
Validate this message against a public key.
Definition: Message.php:248
setConsent($consent)
Set the given consent for this message.
Definition: Message.php:349
toSignedXML()
Convert this message to a signed XML document.
Definition: Message.php:481
getIssueInstant()
Retrieve the issue timestamp of this message.
Definition: Message.php:301
getDestination()
Retrieve the destination of this message.
Definition: Message.php:323
getId()
Retrieve the identifier of this message.
Definition: Message.php:279
getCertificates()
Retrieve the certificates that are included in the message.
Definition: Message.php:548
addValidator($function, $data)
Add a method for validating this message.
Definition: Message.php:225
getIssuer()
Retrieve the issuer if this message.
Definition: Message.php:375
setIssuer($issuer)
Set the issuer of this message.
Definition: Message.php:389
setIssueInstant($issueInstant)
Set the issue timestamp of this message.
Definition: Message.php:311
setSignatureKey(XMLSecurityKey $signatureKey=null)
Set the private key we should use to sign the message.
Definition: Message.php:526
setDestination($destination)
Set the destination of this message.
Definition: Message.php:333
static fromXML(\DOMElement $xml)
Convert an XML element into a message.
Definition: Message.php:562
setId($id)
Set the identifier of this message.
Definition: Message.php:289
getConsent()
Set the given consent for this message.
Definition: Message.php:365
setExtensions($extensions)
Set the Extensions.
Definition: Message.php:603
$key
Definition: croninfo.php:18
if(!array_key_exists('StateId', $_REQUEST)) $id
$xml
Definition: metadata.php:240
$destination
$relayState
$certificates
Definition: metarefresh.php:39