summaryrefslogtreecommitdiffstats
path: root/lib/SAML2
diff options
context:
space:
mode:
authorOlav Morken <olav.morken@uninett.no>2010-04-21 12:56:08 +0000
committerOlav Morken <olav.morken@uninett.no>2010-04-21 12:56:08 +0000
commitd970a850e835bd106bb3920d93bcb09f3a45756d (patch)
treeebb0e124ef0d34b08ab26e2decfe35fddce548cd /lib/SAML2
parentce9c4077c5ea8898eb2480c7c251c27418bf9e53 (diff)
downloadsimplesamlphp-d970a850e835bd106bb3920d93bcb09f3a45756d.zip
simplesamlphp-d970a850e835bd106bb3920d93bcb09f3a45756d.tar.gz
simplesamlphp-d970a850e835bd106bb3920d93bcb09f3a45756d.tar.bz2
SAML2: Metadata XML classes.
git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@2261 44740490-163a-0410-bde0-09ae8108e29a
Diffstat (limited to 'lib/SAML2')
-rw-r--r--lib/SAML2/SignedElementHelper.php216
-rw-r--r--lib/SAML2/XML/Chunk.php104
-rw-r--r--lib/SAML2/XML/ds/KeyInfo.php94
-rw-r--r--lib/SAML2/XML/ds/KeyName.php45
-rw-r--r--lib/SAML2/XML/ds/X509Certificate.php45
-rw-r--r--lib/SAML2/XML/ds/X509Data.php74
-rw-r--r--lib/SAML2/XML/md/AdditionalMetadataLocation.php62
-rw-r--r--lib/SAML2/XML/md/AffiliationDescriptor.php162
-rw-r--r--lib/SAML2/XML/md/AttributeAuthorityDescriptor.php128
-rw-r--r--lib/SAML2/XML/md/AttributeConsumingService.php124
-rw-r--r--lib/SAML2/XML/md/AuthnAuthorityDescriptor.php94
-rw-r--r--lib/SAML2/XML/md/ContactPerson.php182
-rw-r--r--lib/SAML2/XML/md/EndpointType.php87
-rw-r--r--lib/SAML2/XML/md/EntitiesDescriptor.php141
-rw-r--r--lib/SAML2/XML/md/EntityDescriptor.php251
-rw-r--r--lib/SAML2/XML/md/Extensions.php54
-rw-r--r--lib/SAML2/XML/md/IDPSSODescriptor.php145
-rw-r--r--lib/SAML2/XML/md/IndexedEndpointType.php71
-rw-r--r--lib/SAML2/XML/md/KeyDescriptor.php97
-rw-r--r--lib/SAML2/XML/md/Organization.php105
-rw-r--r--lib/SAML2/XML/md/PDPDescriptor.php94
-rw-r--r--lib/SAML2/XML/md/RequestedAttribute.php54
-rw-r--r--lib/SAML2/XML/md/RoleDescriptor.php208
-rw-r--r--lib/SAML2/XML/md/SPSSODescriptor.php107
-rw-r--r--lib/SAML2/XML/md/SSODescriptorType.php114
-rw-r--r--lib/SAML2/XML/md/UnknownRoleDescriptor.php41
-rw-r--r--lib/SAML2/XML/mdattr/EntityAttributes.php70
-rw-r--r--lib/SAML2/XML/saml/Attribute.php121
-rw-r--r--lib/SAML2/XML/saml/AttributeValue.php92
-rw-r--r--lib/SAML2/XML/shibmd/Scope.php74
30 files changed, 3256 insertions, 0 deletions
diff --git a/lib/SAML2/SignedElementHelper.php b/lib/SAML2/SignedElementHelper.php
new file mode 100644
index 0000000..ecae866
--- /dev/null
+++ b/lib/SAML2/SignedElementHelper.php
@@ -0,0 +1,216 @@
+<?php
+
+/**
+ * Helper class for processing signed elements.
+ *
+ * Can either be inherited from, or can be used by proxy.
+ *
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class SAML2_SignedElementHelper implements SAML2_SignedElement {
+
+ /**
+ * The private key we should use to sign the message.
+ *
+ * The private key can be NULL, in which case the message is sent unsigned.
+ *
+ * @var XMLSecurityKey|NULL
+ */
+ private $signatureKey;
+
+
+ /**
+ * List of certificates that should be included in the message.
+ *
+ * @var array
+ */
+ private $certificates;
+
+
+ /**
+ * Available methods for validating this message.
+ *
+ * @var array
+ */
+ private $validators;
+
+
+ /**
+ * Initialize the helper class.
+ *
+ * @param DOMElement|NULL $xml The XML element which may be signed.
+ */
+ protected function __construct(DOMElement $xml = NULL) {
+
+ $this->certificates = array();
+ $this->validators = array();
+
+ if ($xml === NULL) {
+ return;
+ }
+
+ /* Validate the signature element of the message. */
+ try {
+ $sig = SAML2_Utils::validateElement($xml);
+
+ if ($sig !== FALSE) {
+ $this->certificates = $sig['Certificates'];
+ $this->validators[] = array(
+ 'Function' => array('SAML2_Utils', 'validateSignature'),
+ 'Data' => $sig,
+ );
+ }
+
+ } catch (Exception $e) {
+ /* Ignore signature validation errors. */
+ }
+ }
+
+
+ /**
+ * Add a method for validating this element.
+ *
+ * This function is used for custom validation extensions
+ *
+ * @param callback $function The function which should be called.
+ * @param mixed $data The data that should be included as the first parameter to the function.
+ */
+ public function addValidator($function, $data) {
+ assert('is_callable($function)');
+
+ $this->validators[] = array(
+ 'Function' => $function,
+ 'Data' => $data,
+ );
+ }
+
+
+ /**
+ * Validate this element against a public key.
+ *
+ * TRUE is returned on success, FALSE is returned if we don't have any
+ * signature we can validate. An exception is thrown if the signature
+ * validation fails.
+ *
+ * @param XMLSecurityKey $key The key we should check against.
+ * @return boolean TRUE on success, FALSE when we don't have a signature.
+ */
+ public function validate(XMLSecurityKey $key) {
+
+ if (count($this->validators) === 0) {
+ return FALSE;
+ }
+
+ $exceptions = array();
+
+ foreach ($this->validators as $validator) {
+ $function = $validator['Function'];
+ $data = $validator['Data'];
+
+ try {
+ call_user_func($function, $data, $key);
+ /* We were able to validate the message with this validator. */
+ return TRUE;
+ } catch (Exception $e) {
+ $exceptions[] = $e;
+ }
+ }
+
+ /* No validators were able to validate the message. */
+ throw $exceptions[0];
+ }
+
+
+ /**
+ * Retrieve the private key we should use to sign the message.
+ *
+ * @return XMLSecurityKey|NULL The key, or NULL if no key is specified.
+ */
+ public function getSignatureKey() {
+ return $this->signatureKey;
+ }
+
+
+ /**
+ * Set the private key we should use to sign the message.
+ *
+ * If the key is NULL, the message will be sent unsigned.
+ *
+ * @param XMLSecurityKey|NULL $key
+ */
+ public function setSignatureKey(XMLsecurityKey $signatureKey = NULL) {
+ $this->signatureKey = $signatureKey;
+ }
+
+
+ /**
+ * Set the certificates that should be included in the message.
+ *
+ * The certificates should be strings with the PEM encoded data.
+ *
+ * @param array $certificates An array of certificates.
+ */
+ public function setCertificates(array $certificates) {
+ $this->certificates = $certificates;
+ }
+
+
+ /**
+ * Retrieve the certificates that are included in the message.
+ *
+ * @return array An array of certificates.
+ */
+ public function getCertificates() {
+ return $this->certificates;
+ }
+
+
+ /**
+ * Retrieve certificates that sign this element.
+ *
+ * @return array Array with certificates.
+ */
+ public function getValidatingCertificates() {
+
+ $ret = array();
+ foreach ($this->certificates as $cert) {
+
+ /* We have found a matching fingerprint. */
+ $pemCert = "-----BEGIN CERTIFICATE-----\n" .
+ chunk_split($cert, 64) .
+ "-----END CERTIFICATE-----\n";
+
+ /* Extract the public key from the certificate for validation. */
+ $key = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type'=>'public'));
+ $key->loadKey($pemCert);
+
+ /* Check the signature. */
+ if ($this->validate($key)) {
+ $ret[] = $cert;
+ }
+ }
+
+ return $ret;
+ }
+
+
+ /**
+ * Sign the given XML element.
+ *
+ * @param DOMElement $root The element we should sign.
+ * @param DOMElement|NULL $insertBefore The element we should insert the signature node before.
+ */
+ protected function signElement(DOMElement $root, DOMElement $insertBefore = NULL) {
+
+ if ($this->signatureKey === NULL) {
+ /* We cannot sign this element. */
+ return;
+ }
+
+ SAML2_Utils::insertSignature($this->signatureKey, $this->certificates, $root, $insertBefore);
+
+ return $root;
+ }
+
+}
diff --git a/lib/SAML2/XML/Chunk.php b/lib/SAML2/XML/Chunk.php
new file mode 100644
index 0000000..fb47928
--- /dev/null
+++ b/lib/SAML2/XML/Chunk.php
@@ -0,0 +1,104 @@
+<?php
+
+/**
+ * Serializable class used to hold an XML element.
+ *
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class SAML2_XML_Chunk {
+
+ /**
+ * The localName of the element.
+ *
+ * @var string
+ */
+ public $localName;
+
+
+ /**
+ * The namespaceURI of this element.
+ *
+ * @var string
+ */
+ public $namespaceURI;
+
+
+ /**
+ * The DOMElement we contain.
+ *
+ * @var DOMElement
+ */
+ private $xml;
+
+
+ /**
+ * The DOMElement as a text string. Used during serialization.
+ *
+ * @var string|NULL
+ */
+ private $xmlString;
+
+
+ /**
+ * Create a XMLChunk from a copy of the given DOMElement.
+ *
+ * @param DOMElement $xml The element we should copy.
+ */
+ public function __construct(DOMElement $xml) {
+
+ $this->localName = $xml->localName;
+ $this->namespaceURI = $xml->namespaceURI;
+
+ $this->xml = SAML2_Utils::copyElement($xml);
+ }
+
+
+ /**
+ * Get this DOMElement.
+ *
+ * @return DOMElement This element.
+ */
+ public function getXML() {
+ assert('$this->xml instanceof DOMElement || is_string($this->xmlString)');
+
+ if ($this->xml === NULL) {
+ $doc = new DOMDocument();
+ $doc->loadXML($this->xmlString);
+ $this->xml = $doc->firstChild;
+ }
+
+ return $this->xml;
+ }
+
+
+ /**
+ * Append this XML element to a different XML element.
+ *
+ * @param DOMElement $parent The element we should append this element to.
+ * @return DOMElement The new element.
+ */
+ public function toXML(DOMElement $parent) {
+
+ return SAML2_Utils::copyElement($this->getXML(), $parent);
+ }
+
+
+ /**
+ * Serialization handler.
+ *
+ * Converts the XML data to a string that can be serialized
+ *
+ * @return array List of properties that should be serialized.
+ */
+ public function __sleep() {
+ assert('$this->xml instanceof DOMElement || is_string($this->xmlString)');
+
+ if ($this->xmlString === NULL) {
+ $this->xmlString = $this->xml->ownerDocument->saveXML($this->xml);
+ }
+
+ return array('xmlString');
+ }
+
+}
diff --git a/lib/SAML2/XML/ds/KeyInfo.php b/lib/SAML2/XML/ds/KeyInfo.php
new file mode 100644
index 0000000..44b4b0d
--- /dev/null
+++ b/lib/SAML2/XML/ds/KeyInfo.php
@@ -0,0 +1,94 @@
+<?php
+
+/**
+ * Class representing a ds:KeyInfo element.
+ *
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class SAML2_XML_ds_KeyInfo {
+
+ /**
+ * The Id attribute on this element.
+ *
+ * @var string|NULL
+ */
+ public $Id = NULL;
+
+
+ /**
+ * The various key information elements.
+ *
+ * Array with various elements describing this key.
+ * Unknown elements will be represented by SAML2_XML_Chunk.
+ *
+ * @var array
+ */
+ public $info = array();
+
+
+ /**
+ * Initialize a KeyInfo element.
+ *
+ * @param DOMElement|NULL $xml The XML element we should load.
+ */
+ public function __construct(DOMElement $xml = NULL) {
+
+ if ($xml === NULL) {
+ return;
+ }
+
+ if ($xml->hasAttribute('Id')) {
+ $this->Id = $xml->getAttribute('Id');
+ }
+
+ for ($n = $xml->firstChild; $n !== NULL; $n = $n->nextSibling) {
+ if (!($n instanceof DOMElement)) {
+ continue;
+ }
+
+ if ($n->namespaceURI !== XMLSecurityDSig::XMLDSIGNS) {
+ $this->info[] = new SAML2_XML_Chunk($n);
+ continue;
+ }
+ switch ($n->localName) {
+ case 'KeyName':
+ $this->info[] = new SAML2_XML_ds_KeyName($n);
+ break;
+ case 'X509Data':
+ $this->info[] = new SAML2_XML_ds_X509Data($n);
+ break;
+ default:
+ $this->info[] = new SAML2_XML_Chunk($n);
+ break;
+ }
+ }
+ }
+
+
+ /**
+ * Convert this KeyInfo to XML.
+ *
+ * @param DOMElement $parent The element we should append this KeyInfo to.
+ */
+ public function toXML(DOMElement $parent) {
+ assert('is_null($this->Id) || is_string($this->Id)');
+ assert('is_array($this->info)');
+
+ $doc = $parent->ownerDocument;
+
+ $e = $doc->createElementNS(XMLSecurityDSig::XMLDSIGNS, 'ds:KeyInfo');
+ $parent->appendChild($e);
+
+ if (isset($this->Id)) {
+ $e->setAttribute('Id', $this->Id);
+ }
+
+ foreach ($this->info as $n) {
+ $n->toXML($e);
+ }
+
+ return $e;
+ }
+
+}
diff --git a/lib/SAML2/XML/ds/KeyName.php b/lib/SAML2/XML/ds/KeyName.php
new file mode 100644
index 0000000..6eae3a4
--- /dev/null
+++ b/lib/SAML2/XML/ds/KeyName.php
@@ -0,0 +1,45 @@
+<?php
+
+/**
+ * Class representing a ds:KeyName element.
+ *
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class SAML2_XML_ds_KeyName {
+
+ /**
+ * The key name.
+ *
+ * @var string
+ */
+ public $name;
+
+
+ /**
+ * Initialize a KeyName element.
+ *
+ * @param DOMElement|NULL $xml The XML element we should load.
+ */
+ public function __construct(DOMElement $xml = NULL) {
+
+ if ($xml === NULL) {
+ return;
+ }
+
+ $this->name = $xml->textContent;
+ }
+
+
+ /**
+ * Convert this KeyName element to XML.
+ *
+ * @param DOMElement $parent The element we should append this KeyName element to.
+ */
+ public function toXML(DOMElement $parent) {
+ assert('is_string($this->name)');
+
+ return SAML2_Utils::addString($parent, XMLSecurityDSig::XMLDSIGNS, 'ds:KeyName', $this->name);
+ }
+
+}
diff --git a/lib/SAML2/XML/ds/X509Certificate.php b/lib/SAML2/XML/ds/X509Certificate.php
new file mode 100644
index 0000000..c4dcac1
--- /dev/null
+++ b/lib/SAML2/XML/ds/X509Certificate.php
@@ -0,0 +1,45 @@
+<?php
+
+/**
+ * Class representing a ds:X509Certificate element.
+ *
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class SAML2_XML_ds_X509Certificate {
+
+ /**
+ * The base64-encoded certificate.
+ *
+ * @var string
+ */
+ public $certificate;
+
+
+ /**
+ * Initialize an X509Certificate element.
+ *
+ * @param DOMElement|NULL $xml The XML element we should load.
+ */
+ public function __construct(DOMElement $xml = NULL) {
+
+ if ($xml === NULL) {
+ return;
+ }
+
+ $this->certificate = $xml->textContent;
+ }
+
+
+ /**
+ * Convert this X509Certificate element to XML.
+ *
+ * @param DOMElement $parent The element we should append this X509Certificate element to.
+ */
+ public function toXML(DOMElement $parent) {
+ assert('is_string($this->certificate)');
+
+ return SAML2_Utils::addString($parent, XMLSecurityDSig::XMLDSIGNS, 'ds:X509Certificate', $this->certificate);
+ }
+
+}
diff --git a/lib/SAML2/XML/ds/X509Data.php b/lib/SAML2/XML/ds/X509Data.php
new file mode 100644
index 0000000..e6b3c06
--- /dev/null
+++ b/lib/SAML2/XML/ds/X509Data.php
@@ -0,0 +1,74 @@
+<?php
+
+/**
+ * Class representing a ds:X509Data element.
+ *
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class SAML2_XML_ds_X509Data {
+
+ /**
+ * The various X509 data elements.
+ *
+ * Array with various elements describing this certificate.
+ * Unknown elements will be represented by SAML2_XML_Chunk.
+ *
+ * @var array
+ */
+ public $data = array();
+
+
+ /**
+ * Initialize a X509Data.
+ *
+ * @param DOMElement|NULL $xml The XML element we should load.
+ */
+ public function __construct(DOMElement $xml = NULL) {
+
+ if ($xml === NULL) {
+ return;
+ }
+
+ for ($n = $xml->firstChild; $n !== NULL; $n = $n->nextSibling) {
+ if (!($n instanceof DOMElement)) {
+ continue;
+ }
+
+ if ($n->namespaceURI !== XMLSecurityDSig::XMLDSIGNS) {
+ $this->data[] = new SAML2_XML_Chunk($n);
+ continue;
+ }
+ switch ($n->localName) {
+ case 'X509Certificate':
+ $this->data[] = new SAML2_XML_ds_X509Certificate($n);
+ break;
+ default:
+ $this->data[] = new SAML2_XML_Chunk($n);
+ break;
+ }
+ }
+ }
+
+
+ /**
+ * Convert this X509Data element to XML.
+ *
+ * @param DOMElement $parent The element we should append this X509Data element to.
+ */
+ public function toXML(DOMElement $parent) {
+ assert('is_array($this->data)');
+
+ $doc = $parent->ownerDocument;
+
+ $e = $doc->createElementNS(XMLSecurityDSig::XMLDSIGNS, 'ds:X509Data');
+ $parent->appendChild($e);
+
+ foreach ($this->data as $n) {
+ $n->toXML($e);
+ }
+
+ return $e;
+ }
+
+}
diff --git a/lib/SAML2/XML/md/AdditionalMetadataLocation.php b/lib/SAML2/XML/md/AdditionalMetadataLocation.php
new file mode 100644
index 0000000..3bdb6ba
--- /dev/null
+++ b/lib/SAML2/XML/md/AdditionalMetadataLocation.php
@@ -0,0 +1,62 @@
+<?php
+
+/**
+ * Class representing SAML 2 metadata AdditionalMetadataLocation element.
+ *
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class SAML2_XML_md_AdditionalMetadataLocation {
+
+ /**
+ * The namespace of this metadata.
+ *
+ * @var string
+ */
+ public $namespace;
+
+ /**
+ * The URI where the metadata is located.
+ *
+ * @var string
+ */
+ public $location;
+
+
+ /**
+ * Initialize an AdditionalMetadataLocation element.
+ *
+ * @param DOMElement|NULL $xml The XML element we should load.
+ */
+ public function __construct(DOMElement $xml = NULL) {
+
+ if ($xml === NULL) {
+ return;
+ }
+
+ if (!$xml->hasAttribute('namespace')) {
+ throw new Exception('Missing namespace attribute on AdditionalMetadataLocation element.');
+ }
+ $this->namespace = $xml->getAttribute('namespace');
+
+ $this->location = $xml->textContent;
+ }
+
+
+ /**
+ * Convert this AdditionalMetadataLocation to XML.
+ *
+ * @param DOMElement $parent The element we should append to.
+ * @return DOMElement This AdditionalMetadataLocation-element.
+ */
+ public function toXML(DOMElement $parent) {
+ assert('is_string($this->namespace)');
+ assert('is_string($this->location)');
+
+ $e = SAML2_Utils::addString($parent, SAML2_Const::NS_MD, 'md:AdditionalMetadataLocation', $this->location);
+ $e->setAttribute('namespace', $this->namespace);
+
+ return $e;
+ }
+
+}
diff --git a/lib/SAML2/XML/md/AffiliationDescriptor.php b/lib/SAML2/XML/md/AffiliationDescriptor.php
new file mode 100644
index 0000000..ad33323
--- /dev/null
+++ b/lib/SAML2/XML/md/AffiliationDescriptor.php
@@ -0,0 +1,162 @@
+<?php
+
+/**
+ * Class representing SAML 2 AffiliationDescriptor element.
+ *
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class SAML2_XML_md_AffiliationDescriptor extends SAML2_SignedElementHelper {
+
+ /**
+ * The affiliationOwnerID.
+ *
+ * @var string
+ */
+ public $affiliationOwnerID;
+
+
+ /**
+ * The ID of this element.
+ *
+ * @var string|NULL
+ */
+ public $ID;
+
+
+ /**
+ * How long this element is valid, as a unix timestamp.
+ *
+ * @var int|NULL
+ */
+ public $validUntil;
+
+
+ /**
+ * The length of time this element can be cached, as string.
+ *
+ * @var string|NULL
+ */
+ public $cacheDuration;
+
+
+ /**
+ * Extensions on this element.
+ *
+ * Array of extension elements.
+ *
+ * @var array
+ */
+ public $Extensions = array();
+
+
+ /**
+ * The AffiliateMember(s).
+ *
+ * Array of entity ID strings.
+ *
+ * @var array
+ */
+ public $AffiliateMember = array();
+
+
+ /**
+ * KeyDescriptor elements.
+ *
+ * Array of SAML2_XML_md_KeyDescriptor elements.
+ *
+ * @var array
+ */
+ public $KeyDescriptor = array();
+
+
+ /**
+ * Initialize a AffiliationDescriptor.
+ *
+ * @param DOMElement|NULL $xml The XML element we should load.
+ */
+ public function __construct(DOMElement $xml = NULL) {
+
+ parent::__construct($xml);
+
+ if ($xml === NULL) {
+ return;
+ }
+
+ if (!$xml->hasAttribute('affiliationOwnerID')) {
+ throw new Exception('Missing affiliationOwnerID on AffiliationDescriptor.');
+ }
+ $this->affiliationOwnerID = $xml->getAttribute('affiliationOwnerID');
+
+ if ($xml->hasAttribute('ID')) {
+ $this->ID = $xml->getAttribute('ID');
+ }
+
+ if ($xml->hasAttribute('validUntil')) {
+ $this->validUntil = SimpleSAML_Utilities::parseSAML2Time($xml->getAttribute('validUntil'));
+ }
+
+ if ($xml->hasAttribute('cacheDuration')) {
+ $this->cacheDuration = $xml->getAttribute('cacheDuration');
+ }
+
+ $this->Extensions = SAML2_XML_md_Extensions::getList($xml);
+
+ $this->AffiliateMember = SAML2_Utils::extractStrings($xml, './saml_metadata:AffiliateMember');
+ if (empty($this->AffiliateMember)) {
+ throw new Exception('Missing AffiliateMember in AffiliationDescriptor.');
+ }
+
+ foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:KeyDescriptor') as $kd) {
+ $this->KeyDescriptor[] = new SAML2_XML_md_KeyDescriptor($kd);
+ }
+ }
+
+
+ /**
+ * Add this AffiliationDescriptor to an EntityDescriptor.
+ *
+ * @param DOMElement $parent The EntityDescriptor we should append this endpoint to.
+ * @param string $name The name of the element we should create.
+ */
+ public function toXML(DOMElement $parent) {
+ assert('is_string($this->affiliationOwnerID)');
+ assert('is_null($this->ID) || is_string($this->ID)');
+ assert('is_null($this->validUntil) || is_int($this->validUntil)');
+ assert('is_null($this->cacheDuration) || is_string($this->cacheDuration)');
+ assert('is_array($this->Extensions)');
+ assert('is_array($this->AffiliateMember)');
+ assert('!empty($this->AffiliateMember)');
+ assert('is_array($this->KeyDescriptor)');
+
+ $e = $parent->ownerDocument->createElementNS(SAML2_Const::NS_MD, 'md:AffiliationDescriptor');
+ $parent->appendChild($e);
+
+ $e->setAttribute('affiliationOwnerID', $this->affiliationOwnerID);
+
+ if (isset($this->ID)) {
+ $e->setAttribute('ID', $this->ID);
+ }
+
+ if (isset($this->validUntil)) {
+ $e->setAttribute('validUntil', gmdate('Y-m-d\TH:i:s\Z', $this->validUntil));
+ }
+
+ if (isset($this->cacheDuration)) {
+ $e->setAttribute('cacheDuration', $this->cacheDuration);
+ }
+
+ SAML2_XML_md_Extensions::addList($e, $this->Extensions);
+
+ SAML2_Utils::addStrings($e, SAML2_Const::NS_MD, 'md:AffiliateMember', FALSE, $this->AffiliateMember);
+
+ foreach ($this->KeyDescriptor as $kd) {
+ $kd->toXML($e);
+ }
+
+ $this->signElement($e, $e->firstChild);
+
+ return $e;
+ }
+
+}
diff --git a/lib/SAML2/XML/md/AttributeAuthorityDescriptor.php b/lib/SAML2/XML/md/AttributeAuthorityDescriptor.php
new file mode 100644
index 0000000..bbf9507
--- /dev/null
+++ b/lib/SAML2/XML/md/AttributeAuthorityDescriptor.php
@@ -0,0 +1,128 @@
+<?php
+
+/**
+ * Class representing SAML 2 metadata AttributeAuthorityDescriptor.
+ *
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class SAML2_XML_md_AttributeAuthorityDescriptor extends SAML2_XML_md_RoleDescriptor {
+
+ /**
+ * List of AttributeService endpoints.
+ *
+ * Array with EndpointType objects.
+ *
+ * @var array
+ */
+ public $AttributeService = array();
+
+
+ /**
+ * List of AssertionIDRequestService endpoints.
+ *
+ * Array with EndpointType objects.
+ *
+ * @var array
+ */
+ public $AssertionIDRequestService = array();
+
+
+ /**
+ * List of supported NameID formats.
+ *
+ * Array of strings.
+ *
+ * @var array
+ */
+ public $NameIDFormat = array();
+
+
+ /**
+ * List of supported attribute profiles.
+ *
+ * Array with strings.
+ *
+ * @var array
+ */
+ public $AttributeProfile = array();
+
+
+ /**
+ * List of supported attributes.
+ *
+ * Array with SAML2_XML_saml_Attribute objects.
+ *
+ * @var array
+ */
+ public $Attribute = array();
+
+
+ /**
+ * Initialize an IDPSSODescriptor.
+ *
+ * @param DOMElement|NULL $xml The XML element we should load.
+ */
+ public function __construct(DOMElement $xml = NULL) {
+ parent::__construct('md:AttributeAuthorityDescriptor', $xml);
+
+ if ($xml === NULL) {
+ return;
+ }
+
+ foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:AttributeService') as $ep) {
+ $this->AttributeService[] = new SAML2_XML_md_EndpointType($ep);
+ }
+ if (empty($this->AttributeService)) {
+ throw new Exception('Must have at least one AttributeService in AttributeAuthorityDescriptor.');
+ }
+
+ foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:AssertionIDRequestService') as $ep) {
+ $this->AssertionIDRequestService[] = new SAML2_XML_md_EndpointType($airs);
+ }
+
+ $this->NameIDFormat = SAML2_Utils::extractStrings($xml, './saml_metadata:NameIDFormat');
+
+ $this->AttributeProfile = SAML2_Utils::extractStrings($xml, './saml_metadata:AttributeProfile');
+
+ foreach (SAML2_Utils::xpQuery($xml, './saml_assertion:Attribute') as $a) {
+ $this->Attribute[] = new SAML2_XML_saml_Attribute($a);
+ }
+ }
+
+
+ /**
+ * Add this AttributeAuthorityDescriptor to an EntityDescriptor.
+ *
+ * @param DOMElement $parent The EntityDescriptor we should append this IDPSSODescriptor to.
+ */
+ public function toXML(DOMElement $parent) {
+ assert('is_array($this->AttributeService)');
+ assert('!empty($this->AttributeService)');
+ assert('is_array($this->AssertionIDRequestService)');
+ assert('is_array($this->NameIDFormat)');
+ assert('is_array($this->AttributeProfile)');
+ assert('is_array($this->Attribute)');
+
+ $e = parent::toXML($parent);
+
+ foreach ($this->AttributeService as $ep) {
+ $ep->toXML($e, 'md:AttributeService');
+ }
+
+ foreach ($this->AssertionIDRequestService as $ep) {
+ $ep->toXML($e, 'md:AssertionIDRequestService');
+ }
+
+ SAML2_Utils::addStrings($e, SAML2_Const::NS_MD, 'md:NameIDFormat', FALSE, $this->NameIDFormat);
+
+ SAML2_Utils::addStrings($e, SAML2_Const::NS_MD, 'md:AttributeProfile', FALSE, $this->AttributeProfile);
+
+ foreach ($this->Attribute as $a) {
+ $a->toXML($e);
+ }
+
+ return $e;
+ }
+
+}
diff --git a/lib/SAML2/XML/md/AttributeConsumingService.php b/lib/SAML2/XML/md/AttributeConsumingService.php
new file mode 100644
index 0000000..3e0b6a3
--- /dev/null
+++ b/lib/SAML2/XML/md/AttributeConsumingService.php
@@ -0,0 +1,124 @@
+<?php
+
+/**
+ * Class representing SAML 2 Metadata AttributeConsumingService element.
+ *
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class SAML2_XML_md_AttributeConsumingService {
+
+ /**
+ * The index of this AttributeConsumingService.
+ *
+ * @var int
+ */
+ public $index;
+
+
+ /**
+ * Whether this is the default AttributeConsumingService.
+ *
+ * @var bool|NULL
+ */
+ public $isDefault = NULL;
+
+
+ /**
+ * The ServiceName of this AttributeConsumingService.
+ *
+ * This is an associative array with language => translation.
+ *
+ * @var array
+ */
+ public $ServiceName = array();
+
+
+ /**
+ * The ServiceDescription of this AttributeConsumingService.
+ *
+ * This is an associative array with language => translation.
+ *
+ * @var array
+ */
+ public $ServiceDescription = array();
+
+
+ /**
+ * The RequestedAttribute elements.
+ *
+ * This is an array of SAML_RequestedAttributeType elements.
+ *
+ * @var array
+ */
+ public $RequestedAttribute = array();
+
+
+ /**
+ * Initialize / parse an AttributeConsumingService.
+ *
+ * @param DOMElement|NULL $xml The XML element we should load.
+ */
+ public function __construct(DOMElement $xml = NULL) {
+
+ if ($xml === NULL) {
+ return;
+ }
+
+
+ if (!$xml->hasAttribute('index')) {
+ throw new Exception('Missing index on AttributeConsumingService.');
+ }
+ $this->index = (int)$xml->getAttribute('index');
+
+ $this->isDefault = SAML2_Utils::parseBoolean($xml, 'isDefault', NULL);
+
+ $this->ServiceName = SAML2_Utils::extractLocalizedStrings($xml, './saml_metadata:ServiceName');
+ if (empty($this->ServiceName)) {
+ throw new Exception('Missing ServiceName in AttributeConsumingService.');
+ }
+
+ $this->ServiceDescription = SAML2_Utils::extractLocalizedStrings($xml, './saml_metadata:ServiceDescription');
+
+ foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:RequestedAttribute') as $ra) {
+ $this->RequestedAttribute[] = new SAML2_XML_md_RequestedAttribute($ra);
+ }
+ }
+
+
+ /**
+ * Convert to DOMElement.
+ *
+ * @param DOMElement $parent The element we should append this AttributeConsumingService to.
+ */
+ public function toXML(DOMElement $parent) {
+ assert('is_int($this->index)');
+ assert('is_null($this->isDefault) || is_bool($this->isDefault)');
+ assert('is_array($this->ServiceName)');
+ assert('is_array($this->ServiceDescription)');
+ assert('is_array($this->RequestedAttribute)');
+
+ $doc = $parent->ownerDocument;
+
+ $e = $doc->createElementNS(SAML2_Const::NS_MD, 'md:AttributeConsumingService');
+ $parent->appendChild($e);
+
+ $e->setAttribute('index', (string)$this->index);
+
+ if ($this->isDefault === TRUE) {
+ $e->setAttribute('isDefault', 'true');
+ } elseif ($this->isDefault === FALSE) {
+ $e->setAttribute('isDefault', 'false');
+ }
+
+ SAML2_Utils::addStrings($e, SAML2_Const::NS_MD, 'md:ServiceName', TRUE, $this->ServiceName);
+ SAML2_Utils::addStrings($e, SAML2_Const::NS_MD, 'md:ServiceDescription', TRUE, $this->ServiceDescription);
+
+ foreach ($this->RequestedAttribute as $ra) {
+ $ra->toXML($e);
+ }
+
+ return $e;
+ }
+
+}
diff --git a/lib/SAML2/XML/md/AuthnAuthorityDescriptor.php b/lib/SAML2/XML/md/AuthnAuthorityDescriptor.php
new file mode 100644
index 0000000..9a05982
--- /dev/null
+++ b/lib/SAML2/XML/md/AuthnAuthorityDescriptor.php
@@ -0,0 +1,94 @@
+<?php
+
+/**
+ * Class representing SAML 2 metadata AuthnAuthorityDescriptor.
+ *
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class SAML2_XML_md_AuthnAuthorityDescriptor extends SAML2_XML_md_RoleDescriptor {
+
+ /**
+ * List of AuthnQueryService endpoints.
+ *
+ * Array with EndpointType objects.
+ *
+ * @var array
+ */
+ public $AuthnQueryService = array();
+
+
+ /**
+ * List of AssertionIDRequestService endpoints.
+ *
+ * Array with EndpointType objects.
+ *
+ * @var array
+ */
+ public $AssertionIDRequestService = array();
+
+
+ /**
+ * List of supported NameID formats.
+ *
+ * Array of strings.
+ *
+ * @var array
+ */
+ public $NameIDFormat = array();
+
+
+ /**
+ * Initialize an IDPSSODescriptor.
+ *
+ * @param DOMElement|NULL $xml The XML element we should load.
+ */
+ public function __construct(DOMElement $xml = NULL) {
+ parent::__construct('md:AuthnAuthorityDescriptor', $xml);
+
+ if ($xml === NULL) {
+ return;
+ }
+
+ foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:AuthnQueryService') as $ep) {
+ $this->AuthnQueryService[] = new SAML2_XML_md_EndpointType($ep);
+ }
+ if (empty($this->AuthnQueryService)) {
+ throw new Exception('Must have at least one AuthnQueryService in AuthnAuthorityDescriptor.');
+ }
+
+ foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:AssertionIDRequestService') as $ep) {
+ $this->AssertionIDRequestService[] = new SAML2_XML_md_EndpointType($airs);
+ }
+
+ $this->NameIDFormat = SAML2_Utils::extractStrings($xml, './saml_metadata:NameIDFormat');
+ }
+
+
+ /**
+ * Add this IDPSSODescriptor to an EntityDescriptor.
+ *
+ * @param DOMElement $parent The EntityDescriptor we should append this AuthnAuthorityDescriptor to.
+ */
+ public function toXML(DOMElement $parent) {
+ assert('is_array($this->AuthnQueryService)');
+ assert('!empty($this->AuthnQueryService)');
+ assert('is_array($this->AssertionIDRequestService)');
+ assert('is_array($this->NameIDFormat)');
+
+ $e = parent::toXML($parent);
+
+ foreach ($this->AuthnQueryService as $ep) {
+ $ep->toXML($e, 'md:AuthnQueryService');
+ }
+
+ foreach ($this->AssertionIDRequestService as $ep) {
+ $ep->toXML($e, 'md:AssertionIDRequestService');
+ }
+
+ SAML2_Utils::addStrings($e, SAML2_Const::NS_MD, 'md:NameIDFormat', FALSE, $this->NameIDFormat);
+
+ return $e;
+ }
+
+}
diff --git a/lib/SAML2/XML/md/ContactPerson.php b/lib/SAML2/XML/md/ContactPerson.php
new file mode 100644
index 0000000..ea347c3
--- /dev/null
+++ b/lib/SAML2/XML/md/ContactPerson.php
@@ -0,0 +1,182 @@
+<?php
+
+/**
+ * Class representing SAML 2 ContactPerson.
+ *
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class SAML2_XML_md_ContactPerson {
+
+ /**
+ * The contact type.
+ *
+ * @var string
+ */
+ public $contactType;
+
+
+ /**
+ * Extensions on this element.
+ *
+ * Array of extension elements.
+ *
+ * @var array
+ */
+ public $Extensions = array();
+
+
+ /**
+ * The Company of this contact.
+ *
+ * @var string
+ */
+ public $Company = NULL;
+
+
+ /**
+ * The GivenName of this contact.
+ *
+ * @var string
+ */
+ public $GivenName = NULL;
+
+
+ /**
+ * The SurName of this contact.
+ *
+ * @var string
+ */
+ public $SurName = NULL;
+
+
+ /**
+ * The EmailAddresses of this contact.
+ *
+ * @var array
+ */
+ public $EmailAddress = array();
+
+
+ /**
+ * The TelephoneNumbers of this contact.
+ *
+ * @var array
+ */
+ public $TelephoneNumber = array();
+
+
+ /**
+ * Initialize a ContactPerson element.
+ *
+ * @param DOMElement|NULL $xml The XML element we should load.
+ */
+ public function __construct(DOMElement $xml = NULL) {
+
+ if ($xml === NULL) {
+ return;
+ }
+
+ if (!$xml->hasAttribute('contactType')) {
+ throw new Exception('Missing contactType on ContactPerson.');
+ }
+ $this->contactType = $xml->getAttribute('contactType');
+
+ $this->Extensions = SAML2_XML_md_Extensions::getList($xml);
+
+
+ $this->Company = self::getStringElement($xml, 'Company');
+ $this->GivenName = self::getStringElement($xml, 'GivenName');
+ $this->SurName = self::getStringElement($xml, 'SurName');
+ $this->EmailAddress = self::getStringElements($xml, 'EmailAddress');
+ $this->TelephoneNumber = self::getStringElements($xml, 'TelephoneNumber');
+ }
+
+
+ /**
+ * Retrieve the value of a child DOMElements as an array of strings.
+ *
+ * @param DOMElement $parent The parent element.
+ * @param string $name The name of the child elements.
+ * @return array The value of the child elements.
+ */
+ private static function getStringElements(DOMElement $parent, $name) {
+ assert('is_string($name)');
+
+ $e = SAML2_Utils::xpQuery($parent, './saml_metadata:' . $name);
+
+ $ret = array();
+ foreach ($e as $i) {
+ $ret[] = $i->textContent;
+ }
+
+ return $ret;
+ }
+
+
+ /**
+ * Retrieve the value of a child DOMElement as a string.
+ *
+ * @param DOMElement $parent The parent element.
+ * @param string $name The name of the child element.
+ * @return string|NULL The value of the child element.
+ */
+ private static function getStringElement(DOMElement $parent, $name) {
+ assert('is_string($name)');
+
+ $e = self::getStringElements($parent, $name);
+ if (empty($e)) {
+ return NULL;
+ }
+ if (count($e) > 1) {
+ throw new Exception('More than one ' . $name . ' in ' . $parent->tagName);
+ }
+
+ return $e[0];
+ }
+
+
+ /**
+ * Convert this ContactPerson to XML.
+ *
+ * @param DOMElement $parent The element we should add this contact to.
+ * @return DOMElement The new ContactPerson-element.
+ */
+ public function toXML(DOMElement $parent) {
+ assert('is_string($this->contactType)');
+ assert('is_array($this->Extensions)');
+ assert('is_null($this->Company) || is_string($this->Company)');
+ assert('is_null($this->GivenName) || is_string($this->GivenName)');
+ assert('is_null($this->SurName) || is_string($this->SurName)');
+ assert('is_array($this->EmailAddress)');
+ assert('is_array($this->TelephoneNumber)');
+
+ $doc = $parent->ownerDocument;
+
+ $e = $doc->createElementNS(SAML2_Const::NS_MD, 'md:ContactPerson');
+ $parent->appendChild($e);
+
+ $e->setAttribute('contactType', $this->contactType);
+
+ SAML2_XML_md_Extensions::addList($e, $this->Extensions);
+
+ if (isset($this->Company)) {
+ SAML2_Utils::addString($e, SAML2_Const::NS_MD, 'md:Company', $this->Company);
+ }
+ if (isset($this->GivenName)) {
+ SAML2_Utils::addString($e, SAML2_Const::NS_MD, 'md:GivenName', $this->GivenName);
+ }
+ if (isset($this->SurName)) {
+ SAML2_Utils::addString($e, SAML2_Const::NS_MD, 'md:SurName', $this->SurName);
+ }
+ if (!empty($this->EmailAddress)) {
+ SAML2_Utils::addStrings($e, SAML2_Const::NS_MD, 'md:EmailAddress', FALSE, $this->EmailAddress);
+ }
+ if (!empty($this->TelephoneNumber)) {
+ SAML2_Utils::addStrings($e, SAML2_Const::NS_MD, 'md:TelephoneNumber', FALSE, $this->TelephoneNumber);
+ }
+
+ return $e;
+ }
+
+}
diff --git a/lib/SAML2/XML/md/EndpointType.php b/lib/SAML2/XML/md/EndpointType.php
new file mode 100644
index 0000000..519a0a7
--- /dev/null
+++ b/lib/SAML2/XML/md/EndpointType.php
@@ -0,0 +1,87 @@
+<?php
+
+/**
+ * Class representing SAML 2 EndpointType.
+ *
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class SAML2_XML_md_EndpointType {
+
+ /**
+ * The binding for this endpoint.
+ *
+ * @var string
+ */
+ public $Binding;
+
+
+ /**
+ * The URI to this endpoint.
+ *
+ * @var string
+ */
+ public $Location;
+
+
+ /**
+ * The URI where responses can be delivered.
+ *
+ * @var string|NULL
+ */
+ public $ResponseLocation = NULL;
+
+
+ /**
+ * Initialize an EndpointType.
+ *
+ * @param DOMElement|NULL $xml The XML element we should load.
+ */
+ public function __construct(DOMElement $xml = NULL) {
+
+ if ($xml === NULL) {
+ return;
+ }
+
+ if (!$xml->hasAttribute('Binding')) {
+ throw new Exception('Missing Binding on ' . $xml->tagName);
+ }
+ $this->Binding = $xml->getAttribute('Binding');
+
+ if (!$xml->hasAttribute('Location')) {
+ throw new Exception('Missing Location on ' . $xml->tagName);
+ }
+ $this->Location = $xml->getAttribute('Location');
+
+ if ($xml->hasAttribute('ResponseLocation')) {
+ $this->ResponseLocation = $xml->getAttribute('ResponseLocation');
+ }
+ }
+
+
+ /**
+ * Add this endpoint to an XML element.
+ *
+ * @param DOMElement $parent The element we should append this endpoint to.
+ * @param string $name The name of the element we should create.
+ */
+ public function toXML(DOMElement $parent, $name) {
+ assert('is_string($name)');
+ assert('is_string($this->Binding)');
+ assert('is_string($this->Location)');
+ assert('is_null($this->ResponseLocation) || is_string($this->ResponseLocation)');
+
+ $e = $parent->ownerDocument->createElementNS(SAML2_Const::NS_MD, $name);
+ $parent->appendChild($e);
+
+ $e->setAttribute('Binding', $this->Binding);
+ $e->setAttribute('Location', $this->Location);
+
+ if (isset($this->ResponseLocation)) {
+ $e->setAttribute('ResponseLocation', $this->ResponseLocation);
+ }
+
+ return $e;
+ }
+
+}
diff --git a/lib/SAML2/XML/md/EntitiesDescriptor.php b/lib/SAML2/XML/md/EntitiesDescriptor.php
new file mode 100644
index 0000000..a6b66b8
--- /dev/null
+++ b/lib/SAML2/XML/md/EntitiesDescriptor.php
@@ -0,0 +1,141 @@
+<?php
+
+/**
+ * Class representing SAML 2 EntitiesDescriptor element.
+ *
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class SAML2_XML_md_EntitiesDescriptor extends SAML2_SignedElementHelper {
+
+ /**
+ * The ID of this element.
+ *
+ * @var string|NULL
+ */
+ public $ID;
+
+
+ /**
+ * How long this element is valid, as a unix timestamp.
+ *
+ * @var int|NULL
+ */
+ public $validUntil;
+
+
+ /**
+ * The length of time this element can be cached, as string.
+ *
+ * @var string|NULL
+ */
+ public $cacheDuration;
+
+
+ /**
+ * The name of this entity collection.
+ *
+ * @var string|NULL
+ */
+ public $Name;
+
+
+ /**
+ * Extensions on this element.
+ *
+ * Array of extension elements.
+ *
+ * @var array
+ */
+ public $Extensions = array();
+
+
+ /**
+ * Child EntityDescriptor and EntitiesDescriptor elements.
+ *
+ * @var array
+ */
+ public $children = array();
+
+
+ /**
+ * Initialize an EntitiesDescriptor.
+ *
+ * @param DOMElement|NULL $xml The XML element we should load.
+ */
+ public function __construct(DOMElement $xml = NULL) {
+ parent::__construct($xml);
+
+ if ($xml === NULL) {
+ return;
+ }
+
+ if ($xml->hasAttribute('ID')) {
+ $this->ID = $xml->getAttribute('ID');
+ }
+ if ($xml->hasAttribute('validUntil')) {
+ $this->validUntil = SimpleSAML_Utilities::parseSAML2Time($xml->getAttribute('validUntil'));
+ }
+ if ($xml->hasAttribute('cacheDuration')) {
+ $this->cacheDuration = $xml->getAttribute('cacheDuration');
+ }
+ if ($xml->hasAttribute('Name')) {
+ $this->Name = $xml->getAttribute('Name');
+ }
+
+ $this->Extensions = SAML2_XML_md_Extensions::getList($xml);
+
+ foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:EntityDescriptor|./saml_metadata:EntitiesDescriptor') as $node) {
+ if ($node->localName === 'EntityDescriptor') {
+ $this->children[] = new SAML2_XML_md_EntityDescriptor($node);
+ } else {
+ $this->children[] = new SAML2_XML_md_EntitiesDescriptor($node);
+ }
+ }
+ }
+
+
+ /**
+ * Convert this EntitiesDescriptor to XML.
+ *
+ * @param DOMElement|NULL $parent The EntitiesDescriptor we should append this EntitiesDescriptor to.
+ */
+ public function toXML(DOMElement $parent = NULL) {
+ assert('is_null($this->ID) || is_string($this->ID)');
+ assert('is_null($this->validUntil) || is_int($this->validUntil)');
+ assert('is_null($this->cacheDuration) || is_string($this->cacheDuration)');
+ assert('is_array($this->Extensions)');
+ assert('is_array($this->children)');
+
+ if ($parent === NULL) {
+ $doc = new DOMDocument();
+ $e = $doc->createElementNS(SAML2_Const::NS_MD, 'md:EntitiesDescriptor');
+ } else {
+ $e = $parent->ownerDocument->createElementNS(SAML2_Const::NS_MD, 'md:EntitiesDescriptor');
+ $parent->appendChild($e);
+ }
+
+ if (isset($this->ID)) {
+ $e->setAttribute('ID', $this->ID);
+ }
+
+ if (isset($this->validUntil)) {
+ $e->setAttribute('validUntil', gmdate('Y-m-d\TH:i:s\Z', $this->validUntil));
+ }
+
+ if (isset($this->cacheDuration)) {
+ $e->setAttribute('cacheDuration', $this->cacheDuration);
+ }
+
+ SAML2_XML_md_Extensions::addList($e, $this->Extensions);
+
+ foreach ($this->children as $node) {
+ $node->toXML($e);
+ }
+
+ $this->signElement($e, $e->firstChild);
+
+ return $e;
+ }
+
+}
diff --git a/lib/SAML2/XML/md/EntityDescriptor.php b/lib/SAML2/XML/md/EntityDescriptor.php
new file mode 100644
index 0000000..bd35f14
--- /dev/null
+++ b/lib/SAML2/XML/md/EntityDescriptor.php
@@ -0,0 +1,251 @@
+<?php
+
+/**
+ * Class representing SAML 2 EntityDescriptor element.
+ *
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class SAML2_XML_md_EntityDescriptor extends SAML2_SignedElementHelper {
+
+ /**
+ * The entityID this EntityDescriptor represents.
+ *
+ * @var string
+ */
+ public $entityID;
+
+
+ /**
+ * The ID of this element.
+ *
+ * @var string|NULL
+ */
+ public $ID;
+
+
+ /**
+ * How long this element is valid, as a unix timestamp.
+ *
+ * @var int|NULL
+ */
+ public $validUntil;
+
+
+ /**
+ * The length of time this element can be cached, as string.
+ *
+ * @var string|NULL
+ */
+ public $cacheDuration;
+
+
+ /**
+ * Extensions on this element.
+ *
+ * Array of extension elements.
+ *
+ * @var array
+ */
+ public $Extensions = array();
+
+
+ /**
+ * Array with all roles for this entity.
+ *
+ * Array of SAML2_XML_md_RoleDescriptor objects (and subclasses of RoleDescriptor).
+ *
+ * @var array
+ */
+ public $RoleDescriptor = array();
+
+
+ /**
+ * AffiliationDescriptor of this entity.
+ *
+ * @var SAML2_XML_md_AffiliationDescriptor|NULL
+ */
+ public $AffiliationDescriptor = NULL;
+
+
+ /**
+ * Organization of this entity.
+ *
+ * @var SAML2_XML_md_Organization|NULL
+ */
+ public $Organization = NULL;
+
+
+ /**
+ * ContactPerson elements for this entity.
+ *
+ * @var array
+ */
+ public $ContactPerson = array();
+
+
+ /**
+ * AdditionalMetadataLocation elements for this entity.
+ *
+ * @var array
+ */
+ public $AdditionalMetadataLocation = array();
+
+
+ /**
+ * Initialize an EntitiyDescriptor.
+ *
+ * @param DOMElement|NULL $xml The XML element we should load.
+ */
+ public function __construct(DOMElement $xml = NULL) {
+ parent::__construct($xml);
+
+ if ($xml === NULL) {
+ return;
+ }
+
+ if (!$xml->hasAttribute('entityID')) {
+ throw new Exception('Missing required attribute entityID on EntityDescriptor.');
+ }
+ $this->entityID = $xml->getAttribute('entityID');
+
+ if ($xml->hasAttribute('ID')) {
+ $this->ID = $xml->getAttribute('ID');
+ }
+ if ($xml->hasAttribute('validUntil')) {
+ $this->validUntil = SimpleSAML_Utilities::parseSAML2Time($xml->getAttribute('validUntil'));
+ }
+ if ($xml->hasAttribute('cacheDuration')) {
+ $this->cacheDuration = $xml->getAttribute('cacheDuration');
+ }
+
+ $this->Extensions = SAML2_XML_md_Extensions::getList($xml);
+
+ for ($node = $xml->firstChild; $node !== NULL; $node = $node->nextSibling) {
+ if (!($node instanceof DOMElement)) {
+ continue;
+ }
+
+ if ($node->namespaceURI !== SAML2_Const::NS_MD) {
+ continue;
+ }
+
+ switch ($node->localName) {
+ case 'RoleDescriptor':
+ $this->RoleDescriptor[] = new SAML2_XML_md_UnknownRoleDescriptor($node);
+ break;
+ case 'IDPSSODescriptor':
+ $this->RoleDescriptor[] = new SAML2_XML_md_IDPSSODescriptor($node);
+ break;
+ case 'SPSSODescriptor':
+ $this->RoleDescriptor[] = new SAML2_XML_md_SPSSODescriptor($node);
+ break;
+ case 'AuthnAuthorityDescriptor':
+ $this->RoleDescriptor[] = new SAML2_XML_md_AuthnAuthorityDescriptor($node);
+ break;
+ case 'AttributeAuthorityDescriptor':
+ $this->RoleDescriptor[] = new SAML2_XML_md_AttributeAuthorityDescriptor($node);
+ break;
+ case 'PDPDescriptor':
+ $this->RoleDescriptor[] = new SAML2_XML_md_PDPDescriptor($node);
+ break;
+ }
+ }
+
+ $affiliationDescriptor = SAML2_Utils::xpQuery($xml, './saml_metadata:AffiliationDescriptor');
+ if (count($affiliationDescriptor) > 1) {
+ throw new Exception('More than one AffiliationDescriptor in the entity.');
+ } elseif (!empty($affiliationDescriptor)) {
+ $this->AffiliationDescriptor = new SAML2_XML_md_AffiliationDescriptor($affiliationDescriptor[0]);
+ }
+
+ if (empty($this->RoleDescriptor) && is_null($this->AffiliationDescriptor)) {
+ throw new Exception('Must have either one of the RoleDescriptors or an AffiliationDescriptor in EntityDescriptor.');
+ } elseif (!empty($this->RoleDescriptor) && !is_null($this->AffiliationDescriptor)) {
+ throw new Exception('AffiliationDescriptor cannot be combined with other RoleDescriptor elements in EntityDescriptor.');
+ }
+
+ $organization = SAML2_Utils::xpQuery($xml, './saml_metadata:Organization');
+ if (count($organization) > 1) {
+ throw new Exception('More than one Organization in the entity.');
+ } elseif (!empty($organization)) {
+ $this->Organization = new SAML2_XML_md_Organization($organization[0]);
+ }
+
+ foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:ContactPerson') as $cp) {
+ $this->ContactPerson[] = new SAML2_XML_md_ContactPerson($cp);
+ }
+
+ foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:AdditionalMetadataLocation') as $aml) {
+ $this->AdditionalMetadataLocation[] = new SAML2_XML_md_AdditionalMetadataLocation($aml);
+ }
+ }
+
+
+ /**
+ * Create this EntityDescriptor.
+ *
+ * @param DOMElement|NULL $parent The EntitiesDescriptor we should append this EntityDescriptor to.
+ */
+ public function toXML(DOMElement $parent = NULL) {
+ assert('is_string($this->entityID)');
+ assert('is_null($this->ID) || is_string($this->ID)');
+ assert('is_null($this->validUntil) || is_int($this->validUntil)');
+ assert('is_null($this->cacheDuration) || is_string($this->cacheDuration)');
+ assert('is_array($this->Extensions)');
+ assert('is_array($this->RoleDescriptor)');
+ assert('is_null($this->AffiliationDescriptor) || $this->AffiliationDescriptor instanceof SAML2_XML_md_AffiliationDescriptor');
+ assert('is_null($this->Organization) || $this->Organization instanceof SAML2_XML_md_Organization');
+ assert('is_array($this->ContactPerson)');
+ assert('is_array($this->AdditionalMetadataLocation)');
+
+ if ($parent === NULL) {
+ $doc = new DOMDocument();
+ $e = $doc->createElementNS(SAML2_Const::NS_MD, 'md:EntityDescriptor');
+ } else {
+ $e = $parent->ownerDocument->createElementNS(SAML2_Const::NS_MD, 'md:EntityDescriptor');
+ $parent->appendChild($e);
+ }
+
+ $e->setAttribute('entityID', $this->entityID);
+
+ if (isset($this->ID)) {
+ $e->setAttribute('ID', $this->ID);
+ }
+
+ if (isset($this->validUntil)) {
+ $e->setAttribute('validUntil', gmdate('Y-m-d\TH:i:s\Z', $this->validUntil));
+ }
+
+ if (isset($this->cacheDuration)) {
+ $e->setAttribute('cacheDuration', $this->cacheDuration);
+ }
+
+ SAML2_XML_md_Extensions::addList($e, $this->Extensions);
+
+ foreach ($this->RoleDescriptor as $n) {
+ $n->toXML($e);
+ }
+
+ if (isset($this->AffiliationDescriptor)) {
+ $this->AffiliationDescriptor->toXML($e);
+ }
+
+ if (isset($this->Organization)) {
+ $this->Organization->toXML($e);
+ }
+
+ foreach ($this->ContactPerson as $cp) {
+ $cp->toXML($e);
+ }
+
+ foreach ($this->AdditionalMetadataLocation as $n) {
+ $n->toXML($e);
+ }
+
+ $this->signElement($e, $e->firstChild);
+
+ return $e;
+ }
+
+}
diff --git a/lib/SAML2/XML/md/Extensions.php b/lib/SAML2/XML/md/Extensions.php
new file mode 100644
index 0000000..2f5e9ae
--- /dev/null
+++ b/lib/SAML2/XML/md/Extensions.php
@@ -0,0 +1,54 @@
+<?php
+
+/**
+ * Class for handling SAML2 metadata extensions.
+ *
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class SAML2_XML_md_Extensions {
+
+ /**
+ * Get a list of Extensions in the given element.
+ *
+ * @param DOMElement $parent The element that may contain the md:Extensions element.
+ * @return array Array of extensions.
+ */
+ public static function getList(DOMElement $parent) {
+
+ $ret = array();
+ foreach (SAML2_Utils::xpQuery($parent, './saml_metadata:Extensions/*') as $node) {
+ if ($node->namespaceURI === SAML2_XML_shibmd_Scope::NS && $node->localName === 'Scope') {
+ $ret[] = new SAML2_XML_shibmd_Scope($node);
+ } elseif ($node->namespaceURI === SAML2_XML_mdattr_EntityAttributes::NS && $node->localName === 'EntityAttributes') {
+ $ret[] = new SAML2_XML_mdattr_EntityAttributes($node);
+ } else {
+ $ret[] = new SAML2_XML_Chunk($node);
+ }
+ }
+
+ return $ret;
+ }
+
+
+ /**
+ * Add a list of Extensions to the given element.
+ *
+ * @param DOMElement $parent The element we should add the extensions to.
+ * @param array $extensions List of extension objects.
+ */
+ public static function addList(DOMElement $parent, array $extensions) {
+
+ if (empty($extensions)) {
+ return;
+ }
+
+ $extElement = $parent->ownerDocument->createElementNS(SAML2_Const::NS_MD, 'md:Extensions');
+ $parent->appendChild($extElement);
+
+ foreach ($extensions as $ext) {
+ $ext->toXML($extElement);
+ }
+ }
+
+}
diff --git a/lib/SAML2/XML/md/IDPSSODescriptor.php b/lib/SAML2/XML/md/IDPSSODescriptor.php
new file mode 100644
index 0000000..67116ce
--- /dev/null
+++ b/lib/SAML2/XML/md/IDPSSODescriptor.php
@@ -0,0 +1,145 @@
+<?php
+
+/**
+ * Class representing SAML 2 IDPSSODescriptor.
+ *
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class SAML2_XML_md_IDPSSODescriptor extends SAML2_XML_md_SSODescriptorType {
+
+ /**
+ * Whether AuthnRequests sent to this IdP should be signed.
+ *
+ * @var bool|NULL
+ */
+ public $WantAuthnRequestsSigned = NULL;
+
+
+ /**
+ * List of SingleSignOnService endpoints.
+ *
+ * Array with EndpointType objects.
+ *
+ * @var array
+ */
+ public $SingleSignOnService = array();
+
+
+ /**
+ * List of NameIDMappingService endpoints.
+ *
+ * Array with EndpointType objects.
+ *
+ * @var array
+ */
+ public $NameIDMappingService = array();
+
+
+ /**
+ * List of AssertionIDRequestService endpoints.
+ *
+ * Array with EndpointType objects.
+ *
+ * @var array
+ */
+ public $AssertionIDRequestService = array();
+
+
+ /**
+ * List of supported attribute profiles.
+ *
+ * Array with strings.
+ *
+ * @var array
+ */
+ public $AttributeProfile = array();
+
+
+ /**
+ * List of supported attributes.
+ *
+ * Array with SAML2_XML_saml_Attribute objects.
+ *
+ * @var array
+ */
+ public $Attribute = array();
+
+
+ /**
+ * Initialize an IDPSSODescriptor.
+ *
+ * @param DOMElement|NULL $xml The XML element we should load.
+ */
+ public function __construct(DOMElement $xml = NULL) {
+ parent::__construct('md:IDPSSODescriptor', $xml);
+
+ if ($xml === NULL) {
+ return;
+ }
+
+ $this->WantAuthnRequestsSigned = SAML2_Utils::parseBoolean($xml, 'WantAuthnRequestsSigned', NULL);
+
+ foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:SingleSignOnService') as $ep) {
+ $this->SingleSignOnService[] = new SAML2_XML_md_EndpointType($ep);
+ }
+
+ foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:NameIDMappingService') as $ep) {
+ $this->NameIDMappingService[] = new SAML2_XML_md_EndpointType($ep);
+ }
+
+ foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:AssertionIDRequestService') as $ep) {
+ $this->AssertionIDRequestService[] = new SAML2_XML_md_EndpointType($airs);
+ }
+
+ $this->AttributeProfile = SAML2_Utils::extractStrings($xml, './saml_metadata:AttributeProfile');
+
+ foreach (SAML2_Utils::xpQuery($xml, './saml_assertion:Attribute') as $a) {
+ $this->Attribute[] = new SAML2_XML_saml_Attribute($a);
+ }
+ }
+
+
+ /**
+ * Add this IDPSSODescriptor to an EntityDescriptor.
+ *
+ * @param DOMElement $parent The EntityDescriptor we should append this IDPSSODescriptor to.
+ */
+ public function toXML(DOMElement $parent) {
+ assert('is_null($this->WantAuthnRequestsSigned) || is_bool($this->WantAuthnRequestsSigned)');
+ assert('is_array($this->SingleSignOnService)');
+ assert('is_array($this->NameIDMappingService)');
+ assert('is_array($this->AssertionIDRequestService)');
+ assert('is_array($this->AttributeProfile)');
+ assert('is_array($this->Attribute)');
+
+ $e = parent::toXML($parent);
+
+ if ($this->WantAuthnRequestsSigned === TRUE) {
+ $e->setAttribute('WantAuthnRequestsSigned', 'true');
+ } elseif ($this->WantAuthnRequestsSigned === FALSE) {
+ $e->setAttribute('WantAuthnRequestsSigned', 'false');
+ }
+
+ foreach ($this->SingleSignOnService as $ep) {
+ $ep->toXML($e, 'md:SingleSignOnService');
+ }
+
+ foreach ($this->NameIDMappingService as $ep) {
+ $ep->toXML($e, 'md:NameIDMappingService');
+ }
+
+ foreach ($this->AssertionIDRequestService as $ep) {
+ $ep->toXML($e, 'md:AssertionIDRequestService');
+ }
+
+ SAML2_Utils::addStrings($e, SAML2_Const::NS_MD, 'md:AttributeProfile', FALSE, $this->AttributeProfile);
+
+ foreach ($this->Attribute as $a) {
+ $a->toXML($e);
+ }
+
+ return $e;
+ }
+
+}
diff --git a/lib/SAML2/XML/md/IndexedEndpointType.php b/lib/SAML2/XML/md/IndexedEndpointType.php
new file mode 100644
index 0000000..c019152
--- /dev/null
+++ b/lib/SAML2/XML/md/IndexedEndpointType.php
@@ -0,0 +1,71 @@
+<?php
+
+/**
+ * Class representing SAML 2 IndexedEndpointType.
+ *
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class SAML2_XML_md_IndexedEndpointType extends SAML2_XML_md_EndpointType {
+
+ /**
+ * The index for this endpoint.
+ *
+ * @var int
+ */
+ public $index;
+
+
+ /**
+ * Whether this endpoint is the default.
+ *
+ * @var bool|NULL
+ */
+ public $isDefault = NULL;
+
+
+ /**
+ * Initialize an IndexedEndpointType.
+ *
+ * @param DOMElement|NULL $xml The XML element we should load.
+ */
+ public function __construct(DOMElement $xml = NULL) {
+ parent::__construct($xml);
+
+ if ($xml === NULL) {
+ return;
+ }
+
+ if (!$xml->hasAttribute('index')) {
+ throw new Exception('Missing index on ' . $xml->tagName);
+ }
+ $this->index = (int)$xml->getAttribute('index');
+
+ $this->isDefault = SAML2_Utils::parseBoolean($xml, 'isDefault', NULL);
+ }
+
+
+ /**
+ * Add this endpoint to an XML element.
+ *
+ * @param DOMElement $parent The element we should append this endpoint to.
+ * @param string $name The name of the element we should create.
+ */
+ public function toXML(DOMElement $parent, $name) {
+ assert('is_string($name)');
+ assert('is_int($this->index)');
+ assert('is_null($this->isDefault) || is_bool($this->isDefault)');
+
+ $e = parent::toXML($parent, $name);
+ $e->setAttribute('index', (string)$this->index);
+
+ if ($this->isDefault === TRUE) {
+ $e->setAttribute('isDefault', 'true');
+ } elseif ($this->isDefault === FALSE) {
+ $e->setAttribute('isDefault', 'false');
+ }
+
+ return $e;
+ }
+
+}
diff --git a/lib/SAML2/XML/md/KeyDescriptor.php b/lib/SAML2/XML/md/KeyDescriptor.php
new file mode 100644
index 0000000..aeaffe9
--- /dev/null
+++ b/lib/SAML2/XML/md/KeyDescriptor.php
@@ -0,0 +1,97 @@
+<?php
+
+/**
+ * Class representing a KeyDescriptor element.
+ *
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class SAML2_XML_md_KeyDescriptor {
+
+ /**
+ * What this key can be used for.
+ *
+ * 'encryption', 'signing' or NULL.
+ *
+ * @var string|NULL
+ */
+ public $use;
+
+
+ /**
+ * The KeyInfo for this key.
+ *
+ * @var SAML2_XML_ds_KeyInfo
+ */
+ public $KeyInfo;
+
+
+ /**
+ * Supported EncryptionMethods.
+ *
+ * Array of SAML2_XML_Chunk objects.
+ *
+ * @var array
+ */
+ public $EncryptionMethod = array();
+
+
+ /**
+ * Initialize an KeyDescriptor.
+ *
+ * @param DOMElement|NULL $xml The XML element we should load.
+ */
+ public function __construct(DOMElement $xml = NULL) {
+
+ if ($xml === NULL) {
+ return;
+ }
+
+ if ($xml->hasAttribute('use')) {
+ $this->use = $xml->getAttribute('use');
+ }
+
+ $keyInfo = SAML2_Utils::xpQuery($xml, './ds:KeyInfo');
+ if (count($keyInfo) > 1) {
+ throw new Exception('More than one ds:KeyInfo in the KeyDescriptor.');
+ } elseif (empty($keyInfo)) {
+ throw new Exception('No ds:KeyInfo in the KeyDescriptor.');
+ }
+ $this->KeyInfo = new SAML2_XML_ds_KeyInfo($keyInfo[0]);
+
+ foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:EncryptionMethod') as $em) {
+ $this->EncryptionMethod[] = new SAML2_XML_Chunk($em);
+ }
+
+ }
+
+
+ /**
+ * Convert this KeyDescriptor to XML.
+ *
+ * @param DOMElement $parent The element we should append this KeyDescriptor to.
+ */
+ public function toXML(DOMElement $parent) {
+ assert('is_null($this->use) || is_string($this->use)');
+ assert('$this->KeyInfo instanceof SAML2_XML_ds_KeyInfo');
+ assert('is_array($this->EncryptionMethod)');
+
+ $doc = $parent->ownerDocument;
+
+ $e = $doc->createElementNS(SAML2_Const::NS_MD, 'md:KeyDescriptor');
+ $parent->appendChild($e);
+
+ if (isset($this->use)) {
+ $e->setAttribute('use', $this->use);
+ }
+
+ $this->KeyInfo->toXML($e);
+
+ foreach ($this->EncryptionMethod as $em) {
+ $em->toXML($e);
+ }
+
+ return $e;
+ }
+
+}
diff --git a/lib/SAML2/XML/md/Organization.php b/lib/SAML2/XML/md/Organization.php
new file mode 100644
index 0000000..3869b04
--- /dev/null
+++ b/lib/SAML2/XML/md/Organization.php
@@ -0,0 +1,105 @@
+<?php
+
+/**
+ * Class representing SAML 2 Organization element.
+ *
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class SAML2_XML_md_Organization {
+
+ /**
+ * Extensions on this element.
+ *
+ * Array of extension elements.
+ *
+ * @var array
+ */
+ public $Extensions = array();
+
+
+ /**
+ * The OrganizationName, as an array of language => translation.
+ *
+ * @var array
+ */
+ public $OrganizationName = array();
+
+
+ /**
+ * The OrganizationDisplayName, as an array of language => translation.
+ *
+ * @var array
+ */
+ public $OrganizationDisplayName = array();
+
+
+ /**
+ * The OrganizationURL, as an array of language => translation.
+ *
+ * @var array
+ */
+ public $OrganizationURL = array();
+
+
+ /**
+ * Initialize an Organization element.
+ *
+ * @param DOMElement|NULL $xml The XML element we should load.
+ */
+ public function __construct(DOMElement $xml = NULL) {
+
+ if ($xml === NULL) {
+ return;
+ }
+
+ $this->Extensions = SAML2_XML_md_Extensions::getList($xml);
+
+
+ $this->OrganizationName = SAML2_Utils::extractLocalizedStrings($xml, './saml_metadata:OrganizationName');
+ if (empty($this->OrganizationName)) {
+ $this->OrganizationName = array('invalid' => '');
+ }
+
+ $this->OrganizationDisplayName = SAML2_Utils::extractLocalizedStrings($xml, './saml_metadata:OrganizationDisplayName');
+ if (empty($this->OrganizationDisplayName)) {
+ $this->OrganizationDisplayName = array('invalid' => '');
+ }
+
+ $this->OrganizationURL = SAML2_Utils::extractLocalizedStrings($xml, './saml_metadata:OrganizationURL');
+ if (empty($this->OrganizationURL)) {
+ $this->OrganizationURL = array('invalid' => '');
+ }
+ }
+
+
+ /**
+ * Convert this Organization to XML.
+ *
+ * @param DOMElement $parent The element we should add this organization to.
+ * @return DOMElement This Organization-element.
+ */
+ public function toXML(DOMElement $parent) {
+ assert('is_array($this->Extensions)');
+ assert('is_array($this->OrganizationName)');
+ assert('!empty($this->OrganizationName)');
+ assert('is_array($this->OrganizationDisplayName)');
+ assert('!empty($this->OrganizationDisplayName)');
+ assert('is_array($this->OrganizationURL)');
+ assert('!empty($this->OrganizationURL)');
+
+ $doc = $parent->ownerDocument;
+
+ $e = $doc->createElementNS(SAML2_Const::NS_MD, 'md:Organization');
+ $parent->appendChild($e);
+
+ SAML2_XML_md_Extensions::addList($e, $this->Extensions);
+
+ SAML2_Utils::addStrings($e, SAML2_Const::NS_MD, 'md:OrganizationName', TRUE, $this->OrganizationName);
+ SAML2_Utils::addStrings($e, SAML2_Const::NS_MD, 'md:OrganizationDisplayName', TRUE, $this->OrganizationDisplayName);
+ SAML2_Utils::addStrings($e, SAML2_Const::NS_MD, 'md:OrganizationURL', TRUE, $this->OrganizationURL);
+
+ return $e;
+ }
+
+}
diff --git a/lib/SAML2/XML/md/PDPDescriptor.php b/lib/SAML2/XML/md/PDPDescriptor.php
new file mode 100644
index 0000000..e2765fd
--- /dev/null
+++ b/lib/SAML2/XML/md/PDPDescriptor.php
@@ -0,0 +1,94 @@
+<?php
+
+/**
+ * Class representing SAML 2 metadata PDPDescriptor.
+ *
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class SAML2_XML_md_PDPDescriptor extends SAML2_XML_md_RoleDescriptor {
+
+ /**
+ * List of AuthzService endpoints.
+ *
+ * Array with EndpointType objects.
+ *
+ * @var array
+ */
+ public $AuthzService = array();
+
+
+ /**
+ * List of AssertionIDRequestService endpoints.
+ *
+ * Array with EndpointType objects.
+ *
+ * @var array
+ */
+ public $AssertionIDRequestService = array();
+
+
+ /**
+ * List of supported NameID formats.
+ *
+ * Array of strings.
+ *
+ * @var array
+ */
+ public $NameIDFormat = array();
+
+
+ /**
+ * Initialize an IDPSSODescriptor.
+ *
+ * @param DOMElement|NULL $xml The XML element we should load.
+ */
+ public function __construct(DOMElement $xml = NULL) {
+ parent::__construct('md:PDPDescriptor', $xml);
+
+ if ($xml === NULL) {
+ return;
+ }
+
+ foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:AuthzService') as $ep) {
+ $this->AuthzService[] = new SAML2_XML_md_EndpointType($ep);
+ }
+ if (empty($this->AuthzService)) {
+ throw new Exception('Must have at least one AuthzService in PDPDescriptor.');
+ }
+
+ foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:AssertionIDRequestService') as $ep) {
+ $this->AssertionIDRequestService[] = new SAML2_XML_md_EndpointType($airs);
+ }
+
+ $this->NameIDFormat = SAML2_Utils::extractStrings($xml, './saml_metadata:NameIDFormat');
+ }
+
+
+ /**
+ * Add this PDPDescriptor to an EntityDescriptor.
+ *
+ * @param DOMElement $parent The EntityDescriptor we should append this IDPSSODescriptor to.
+ */
+ public function toXML(DOMElement $parent) {
+ assert('is_array($this->AuthzService)');
+ assert('!empty($this->AuthzService)');
+ assert('is_array($this->AssertionIDRequestService)');
+ assert('is_array($this->NameIDFormat)');
+
+ $e = parent::toXML($parent);
+
+ foreach ($this->AuthzService as $ep) {
+ $ep->toXML($e, 'md:AuthzService');
+ }
+
+ foreach ($this->AssertionIDRequestService as $ep) {
+ $ep->toXML($e, 'md:AssertionIDRequestService');
+ }
+
+ SAML2_Utils::addStrings($e, SAML2_Const::NS_MD, 'md:NameIDFormat', FALSE, $this->NameIDFormat);
+
+ return $e;
+ }
+
+}
diff --git a/lib/SAML2/XML/md/RequestedAttribute.php b/lib/SAML2/XML/md/RequestedAttribute.php
new file mode 100644
index 0000000..124a25d
--- /dev/null
+++ b/lib/SAML2/XML/md/RequestedAttribute.php
@@ -0,0 +1,54 @@
+<?php
+
+/**
+ * Class representing SAML 2 metadata RequestedAttribute.
+ *
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class SAML2_XML_md_RequestedAttribute extends SAML2_XML_saml_Attribute {
+
+ /**
+ * Whether this attribute is required.
+ *
+ * @var bool|NULL
+ */
+ public $isRequired = NULL;
+
+
+ /**
+ * Initialize an RequestedAttribute.
+ *
+ * @param DOMElement|NULL $xml The XML element we should load.
+ */
+ public function __construct(DOMElement $xml = NULL) {
+ parent::__construct($xml);
+
+ if ($xml === NULL) {
+ return;
+ }
+
+ $this->isRequired = SAML2_Utils::parseBoolean($xml, 'isRequired', NULL);
+ }
+
+
+ /**
+ * Convert this RequestedAttribute to XML.
+ *
+ * @param DOMElement $parent The element we should append this RequestedAttribute to.
+ */
+ public function toXML(DOMElement $parent) {
+ assert('is_bool($this->isRequired) || is_null($this->isRequired)');
+
+ $e = $this->toXMLInternal($parent, SAML2_Const::NS_MD, 'md:RequestedAttribute');
+
+ if ($this->isRequired === TRUE) {
+ $e->setAttribute('isRequired', 'true');
+ } elseif ($this->isRequired === FALSE) {
+ $e->setAttribute('isRequired', 'false');
+ }
+
+ return $e;
+ }
+
+}
diff --git a/lib/SAML2/XML/md/RoleDescriptor.php b/lib/SAML2/XML/md/RoleDescriptor.php
new file mode 100644
index 0000000..346d34c
--- /dev/null
+++ b/lib/SAML2/XML/md/RoleDescriptor.php
@@ -0,0 +1,208 @@
+<?php
+
+/**
+ * Class representing SAML 2 RoleDescriptor element.
+ *
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class SAML2_XML_md_RoleDescriptor extends SAML2_SignedElementHelper {
+
+ /**
+ * The name of this descriptor element.
+ *
+ * @var string
+ */
+ private $elementName;
+
+
+ /**
+ * The ID of this element.
+ *
+ * @var string|NULL
+ */
+ public $ID;
+
+
+ /**
+ * How long this element is valid, as a unix timestamp.
+ *
+ * @var int|NULL
+ */
+ public $validUntil;
+
+
+ /**
+ * The length of time this element can be cached, as string.
+ *
+ * @var string|NULL
+ */
+ public $cacheDuration;
+
+
+ /**
+ * List of supported protocols.
+ *
+ * @var array
+ */
+ public $protocolSupportEnumeration = array();
+
+
+ /**
+ * Error URL for this role.
+ *
+ * @var string|NULL
+ */
+ public $errorURL;
+
+
+ /**
+ * Extensions on this element.
+ *
+ * Array of extension elements.
+ *
+ * @var array
+ */
+ public $Extensions = array();
+
+
+ /**
+ * KeyDescriptor elements.
+ *
+ * Array of SAML2_XML_md_KeyDescriptor elements.
+ *
+ * @var array
+ */
+ public $KeyDescriptor = array();
+
+
+ /**
+ * Organization of this role.
+ *
+ * @var SAML2_XML_md_Organization|NULL
+ */
+ public $Organization = NULL;
+
+
+ /**
+ * ContactPerson elements for this role.
+ *
+ * Array of SAML2_XML_md_ContactPerson objects.
+ *
+ * @var array
+ */
+ public $ContactPerson = array();
+
+
+ /**
+ * Initialize a RoleDescriptor.
+ *
+ * @param string $elementName The name of this element.
+ * @param DOMElement|NULL $xml The XML element we should load.
+ */
+ protected function __construct($elementName, DOMElement $xml = NULL) {
+ assert('is_string($elementName)');
+
+ parent::__construct($xml);
+ $this->elementName = $elementName;
+
+ if ($xml === NULL) {
+ return;
+ }
+
+ if ($xml->hasAttribute('ID')) {
+ $this->ID = $xml->getAttribute('ID');
+ }
+ if ($xml->hasAttribute('validUntil')) {
+ $this->validUntil = SimpleSAML_Utilities::parseSAML2Time($xml->getAttribute('validUntil'));
+ }
+ if ($xml->hasAttribute('cacheDuration')) {
+ $this->cacheDuration = $xml->getAttribute('cacheDuration');
+ }
+
+ if (!$xml->hasAttribute('protocolSupportEnumeration')) {
+ throw new Exception('Missing protocolSupportEnumeration attribute on ' . $xml->localName);
+ }
+ $this->protocolSupportEnumeration = preg_split('/[\s]+/', $xml->getAttribute('protocolSupportEnumeration'));
+
+ if ($xml->hasAttribute('errorURL')) {
+ $this->errorURL = $xml->getAttribute('errorURL');
+ }
+
+
+ $this->Extensions = SAML2_XML_md_Extensions::getList($xml);
+
+ foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:KeyDescriptor') as $kd) {
+ $this->KeyDescriptor[] = new SAML2_XML_md_KeyDescriptor($kd);
+ }
+
+ $organization = SAML2_Utils::xpQuery($xml, './saml_metadata:Organization');
+ if (count($organization) > 1) {
+ throw new Exception('More than one Organization in the entity.');
+ } elseif (!empty($organization)) {
+ $this->Organization = new SAML2_XML_md_Organization($organization[0]);
+ }
+
+ foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:ContactPerson') as $cp) {
+ $this->contactPersons[] = new SAML2_XML_md_ContactPerson($cp);
+ }
+ }
+
+
+ /**
+ * Add this RoleDescriptor to an EntityDescriptor.
+ *
+ * @param DOMElement $parent The EntityDescriptor we should append this endpoint to.
+ * @param string $name The name of the element we should create.
+ */
+ protected function toXML(DOMElement $parent) {
+ assert('is_null($this->ID) || is_string($this->ID)');
+ assert('is_null($this->validUntil) || is_int($this->validUntil)');
+ assert('is_null($this->cacheDuration) || is_string($this->cacheDuration)');
+ assert('is_array($this->protocolSupportEnumeration)');
+ assert('is_null($this->errorURL) || is_string($this->errorURL)');
+ assert('is_array($this->Extensions)');
+ assert('is_array($this->KeyDescriptor)');
+ assert('is_null($this->Organization) || $this->Organization instanceof SAML2_XML_md_Organization');
+ assert('is_array($this->ContactPerson)');
+
+ $e = $parent->ownerDocument->createElementNS(SAML2_Const::NS_MD, $this->elementName);
+ $parent->appendChild($e);
+
+ if (isset($this->ID)) {
+ $e->setAttribute('ID', $this->ID);
+ }
+
+ if (isset($this->validUntil)) {
+ $e->setAttribute('validUntil', gmdate('Y-m-d\TH:i:s\Z', $this->validUntil));
+ }
+
+ if (isset($this->cacheDuration)) {
+ $e->setAttribute('cacheDuration', $this->cacheDuration);
+ }
+
+ $e->setAttribute('protocolSupportEnumeration', implode(' ', $this->protocolSupportEnumeration));
+
+ if (isset($this->errorURL)) {
+ $e->setAttribute('errorURL', $this->errorURL);
+ }
+
+
+ SAML2_XML_md_Extensions::addList($e, $this->Extensions);
+
+ foreach ($this->KeyDescriptor as $kd) {
+ $kd->toXML($e);
+ }
+
+ if (isset($this->Organization)) {
+ $this->Organization->toXML($e);
+ }
+
+ foreach ($this->ContactPerson as $cp) {
+ $cp->toXML($e);
+ }
+
+ return $e;
+ }
+
+}
diff --git a/lib/SAML2/XML/md/SPSSODescriptor.php b/lib/SAML2/XML/md/SPSSODescriptor.php
new file mode 100644
index 0000000..da7077e
--- /dev/null
+++ b/lib/SAML2/XML/md/SPSSODescriptor.php
@@ -0,0 +1,107 @@
+<?php
+
+/**
+ * Class representing SAML 2 SPSSODescriptor.
+ *
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class SAML2_XML_md_SPSSODescriptor extends SAML2_XML_md_SSODescriptorType {
+
+ /**
+ * Whether this SP signs authentication requests.
+ *
+ * @var bool|NULL
+ */
+ public $AuthnRequestsSigned = NULL;
+
+
+ /**
+ * Whether this SP wants the Assertion elements to be signed.
+ *
+ * @var bool|NULL
+ */
+ public $WantAssertionsSigned = NULL;
+
+
+ /**
+ * List of AssertionConsumerService endpoints for this SP.
+ *
+ * Array with IndexedEndpointType objects.
+ *
+ * @var array
+ */
+ public $AssertionConsumerService = array();
+
+
+ /**
+ * List of AttributeConsumingService descriptors for this SP.
+ *
+ * Array with SAML2_XML_md_AttribteConsumingService objects.
+ *
+ * @var array
+ */
+ public $AttributeConsumingService = array();
+
+
+ /**
+ * Initialize a SPSSODescriptor.
+ *
+ * @param DOMElement|NULL $xml The XML element we should load.
+ */
+ public function __construct(DOMElement $xml = NULL) {
+ parent::__construct('md:SPSSODescriptor', $xml);
+
+ if ($xml === NULL) {
+ return;
+ }
+
+ $this->AuthnRequestsSigned = SAML2_Utils::parseBoolean($xml, 'AuthnRequestsSigned', NULL);
+ $this->WantAssertionsSigned = SAML2_Utils::parseBoolean($xml, 'WantAssertionsSigned', NULL);
+
+ foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:AssertionConsumerService') as $ep) {
+ $this->AssertionConsumerService[] = new SAML2_XML_md_IndexedEndpointType($ep);
+ }
+
+ foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:AttributeConsumingService') as $acs) {
+ $this->AttributeConsumingService[] = new SAML2_XML_md_AttributeConsumingService($acs);
+ }
+ }
+
+
+ /**
+ * Add this SPSSODescriptor to an EntityDescriptor.
+ *
+ * @param DOMElement $parent The EntityDescriptor we should append this SPSSODescriptor to.
+ */
+ public function toXML(DOMElement $parent) {
+ assert('is_null($this->AuthnRequestsSigned) || is_bool($this->AuthnRequestsSigned)');
+ assert('is_null($this->WantAssertionsSigned) || is_bool($this->WantAssertionsSigned)');
+ assert('is_array($this->AssertionConsumerService)');
+ assert('is_array($this->AttributeConsumingService)');
+
+ $e = parent::toXML($parent);
+
+ if ($this->AuthnRequestsSigned === TRUE) {
+ $e->setAttribute('AuthnRequestsSigned', 'true');
+ } elseif ($this->AuthnRequestsSigned === FALSE) {
+ $e->setAttribute('AuthnRequestsSigned', 'false');
+ }
+
+ if ($this->WantAssertionsSigned === TRUE) {
+ $e->setAttribute('WantAssertionsSigned', 'true');
+ } elseif ($this->WantAssertionsSigned === FALSE) {
+ $e->setAttribute('WantAssertionsSigned', 'false');
+ }
+
+
+ foreach ($this->AssertionConsumerService as $ep) {
+ $ep->toXML($e, 'md:AssertionConsumerService');
+ }
+
+ foreach ($this->AttributeConsumingService as $acs) {
+ $acs->toXML($e);
+ }
+ }
+
+}
diff --git a/lib/SAML2/XML/md/SSODescriptorType.php b/lib/SAML2/XML/md/SSODescriptorType.php
new file mode 100644
index 0000000..4ba5f5a
--- /dev/null
+++ b/lib/SAML2/XML/md/SSODescriptorType.php
@@ -0,0 +1,114 @@
+<?php
+
+/**
+ * Class representing SAML 2 SSODescriptorType.
+ *
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+abstract class SAML2_XML_md_SSODescriptorType extends SAML2_XML_md_RoleDescriptor {
+
+ /**
+ * List of ArtifactResolutionService endpoints.
+ *
+ * Array with IndexedEndpointType objects.
+ *
+ * @var array
+ */
+ public $ArtifactResolutionService = array();
+
+
+ /**
+ * List of SingleLogoutService endpoints.
+ *
+ * Array with EndpointType objects.
+ *
+ * @var array
+ */
+ public $SingleLogoutService = array();
+
+
+ /**
+ * List of ManageNameIDService endpoints.
+ *
+ * Array with EndpointType objects.
+ *
+ * @var array
+ */
+ public $ManageNameIDService = array();
+
+
+ /**
+ * List of supported NameID formats.
+ *
+ * Array of strings.
+ *
+ * @var array
+ */
+ public $NameIDFormat = array();
+
+
+ /**
+ * Initialize a SSODescriptor.
+ *
+ * @param string $elementName The name of this element.
+ * @param DOMElement|NULL $xml The XML element we should load.
+ */
+ protected function __construct($elementName, DOMElement $xml = NULL) {
+ assert('is_string($elementName)');
+
+ parent::__construct($elementName, $xml);
+
+ if ($xml === NULL) {
+ return;
+ }
+
+ foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:ArtifactResolutionService') as $ep) {
+ $this->ArtifactResolutionService[] = new SAML2_XML_md_IndexedEndpointType($ep);
+ }
+
+ foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:SingleLogoutService') as $ep) {
+ $this->SingleLogoutService[] = new SAML2_XML_md_EndpointType($ep);
+ }
+
+ foreach (SAML2_Utils::xpQuery($xml, './saml_metadata:ManageNameIDService') as $ep) {
+ $this->ManageNameIDService[] = new SAML2_XML_md_EndpointType($ep);
+ }
+
+ $this->NameIDFormat = SAML2_Utils::extractStrings($xml, './saml_metadata:NameIDFormat');
+ }
+
+
+ /**
+ * Add this SSODescriptorType to an EntityDescriptor.
+ *
+ * @param DOMElement $parent The EntityDescriptor we should append this SSODescriptorType to.
+ * @param string $name The name of the element we should create.
+ * @return DOMElement The generated SSODescriptor DOMElement.
+ */
+ protected function toXML(DOMElement $parent) {
+ assert('is_array($this->ArtifactResolutionService)');
+ assert('is_array($this->SingleLogoutService)');
+ assert('is_array($this->ManageNameIDService)');
+ assert('is_array($this->NameIDFormat)');
+
+ $e = parent::toXML($parent);
+
+ foreach ($this->ArtifactResolutionService as $ep) {
+ $ep->toXML($e, 'md:ArtifactResolutionService');
+ }
+
+ foreach ($this->SingleLogoutService as $ep) {
+ $ep->toXML($e, 'md:SingleLogoutService');
+ }
+
+ foreach ($this->ManageNameIDService as $ep) {
+ $ep->toXML($e, 'md:ManageNameIDService');
+ }
+
+ SAML2_Utils::addStrings($e, SAML2_Const::NS_MD, 'md:NameIDFormat', FALSE, $this->NameIDFormat);
+
+ return $e;
+ }
+
+}
diff --git a/lib/SAML2/XML/md/UnknownRoleDescriptor.php b/lib/SAML2/XML/md/UnknownRoleDescriptor.php
new file mode 100644
index 0000000..66e3a79
--- /dev/null
+++ b/lib/SAML2/XML/md/UnknownRoleDescriptor.php
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * Class representing unknown RoleDescriptors.
+ *
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class SAML2_XML_md_UnknownRoleDescriptor extends SAML2_XML_md_RoleDescriptor {
+
+ /**
+ * This RoleDescriptor as XML
+ *
+ * @var SAML2_XML_Chunk
+ */
+ private $xml;
+
+
+ /**
+ * Initialize an unknown RoleDescriptor.
+ *
+ * @param DOMElement $xml The XML element we should load.
+ */
+ public function __construct(DOMElement $xml) {
+ parent::__construct('md:RoleDescriptor', $xml);
+
+ $this->xml = new SAML2_XML_Chunk($xml);
+ }
+
+
+ /**
+ * Add this RoleDescriptor to an EntityDescriptor.
+ *
+ * @param DOMElement $parent The EntityDescriptor we should append this RoleDescriptor to.
+ */
+ public function toXML(DOMElement $parent) {
+
+ $this->xml->toXML($parent);
+ }
+
+}
diff --git a/lib/SAML2/XML/mdattr/EntityAttributes.php b/lib/SAML2/XML/mdattr/EntityAttributes.php
new file mode 100644
index 0000000..a530569
--- /dev/null
+++ b/lib/SAML2/XML/mdattr/EntityAttributes.php
@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * Class for handling the EntityAttributes metadata extension.
+ *
+ * @link: http://docs.oasis-open.org/security/saml/Post2.0/sstc-metadata-attr-cs-01.pdf
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class SAML2_XML_mdattr_EntityAttributes {
+
+ /**
+ * The namespace used for the EntityAttributes extension.
+ */
+ const NS = 'urn:oasis:names:tc:SAML:metadata:attribute';
+
+
+ /**
+ * Array with child elements.
+ *
+ * The elements can be SAML2_XML_saml_Attribute or SAML2_XML_Chunk elements.
+ *
+ * @var array
+ */
+ public $children;
+
+
+ /**
+ * Create a EntityAttributes element.
+ *
+ * @param DOMElement|NULL $xml The XML element we should load.
+ */
+ public function __construct(DOMElement $xml = NULL) {
+
+ if ($xml === NULL) {
+ return;
+ }
+
+ foreach (SAML2_Utils::xpQuery($xml, './saml_assertion:Attribute|./saml_assertion:Assertion') as $node) {
+ if ($node->localName === 'Attribute') {
+ $this->children[] = new SAML2_XML_saml_Attribute($node);
+ } else {
+ $this->children[] = new SAML2_XML_Chunk($node);
+ }
+ }
+
+ }
+
+
+ /**
+ * Convert this EntityAttributes to XML.
+ *
+ * @param DOMElement $parent The element we should append to.
+ */
+ public function toXML(DOMElement $parent) {
+ assert('is_array($this->children)');
+
+ $doc = $parent->ownerDocument;
+
+ $e = $doc->createElementNS(SAML2_XML_mdattr_EntityAttributes::NS, 'mdattr:EntityAttributes');
+ $parent->appendChild($e);
+
+ foreach ($this->children as $child) {
+ $child->toXML($e);
+ }
+
+ return $e;
+ }
+
+}
diff --git a/lib/SAML2/XML/saml/Attribute.php b/lib/SAML2/XML/saml/Attribute.php
new file mode 100644
index 0000000..afbf0cb
--- /dev/null
+++ b/lib/SAML2/XML/saml/Attribute.php
@@ -0,0 +1,121 @@
+<?php
+
+/**
+ * Class representing SAML 2 Attribute.
+ *
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class SAML2_XML_saml_Attribute {
+
+ /**
+ * The Name of this attribute.
+ *
+ * @var string
+ */
+ public $Name;
+
+
+ /**
+ * The NameFormat of this attribute.
+ *
+ * @var string|NULL
+ */
+ public $NameFormat;
+
+
+ /**
+ * The FriendlyName of this attribute.
+ *
+ * @var string|NULL
+ */
+ public $FriendlyName = NULL;
+
+
+ /**
+ * List of attribute values.
+ *
+ * Array of SAML2_XML_saml_AttributeValue elements.
+ *
+ * @var array
+ */
+ public $AttributeValue = array();
+
+
+ /**
+ * Initialize an Attribute.
+ *
+ * @param DOMElement|NULL $xml The XML element we should load.
+ */
+ public function __construct(DOMElement $xml = NULL) {
+
+ if ($xml === NULL) {
+ return;
+ }
+
+ if (!$xml->hasAttribute('Name')) {
+ throw new Exception('Missing Name on Attribute.');
+ }
+ $this->Name = $xml->getAttribute('Name');
+
+ if ($xml->hasAttribute('NameFormat')) {
+ $this->NameFormat = $xml->getAttribute('NameFormat');
+ }
+
+ if ($xml->hasAttribute('FriendlyName')) {
+ $this->FriendlyName = $xml->getAttribute('FriendlyName');
+ }
+
+ foreach (SAML2_Utils::xpQuery($xml, './saml_assertion:AttributeValue') as $av) {
+ $this->AttributeValue[] = new SAML2_XML_saml_AttributeValue($av);
+ }
+ }
+
+
+ /**
+ * Internal implementation of toXML.
+ * This function allows RequestedAttribute to specify the element name and namespace.
+ *
+ * @param DOMElement $parent The element we should append this Attribute to.
+ * @param string $namespace The namespace the element should be created in.
+ * @param string $name The name of the element.
+ */
+ protected function toXMLInternal(DOMElement $parent, $namespace, $name) {
+ assert('is_string($namespace)');
+ assert('is_string($name)');
+ assert('is_string($this->Name)');
+ assert('is_null($this->NameFormat) || is_string($this->NameFormat)');
+ assert('is_null($this->FriendlyName) || is_string($this->FriendlyName)');
+ assert('is_array($this->AttributeValue)');
+
+ $e = $parent->ownerDocument->createElementNS($namespace, $name);
+ $parent->appendChild($e);
+
+ $e->setAttribute('Name', $this->Name);
+
+ if (isset($this->NameFormat)) {
+ $e->setAttribute('NameFormat', $this->NameFormat);
+ }
+
+ if (isset($this->FriendlyName)) {
+ $e->setAttribute('FriendlyName', $this->FriendlyName);
+ }
+
+ foreach ($this->AttributeValue as $av) {
+ $av->toXML($e);
+ }
+
+ return $e;
+ }
+
+
+ /**
+ * Convert this Attribute to XML.
+ *
+ * @param DOMElement $parent The element we should append this Attribute to.
+ */
+ public function toXML(DOMElement $parent) {
+ return $this->toXMLInternal($parent, SAML2_Const::NS_SAML, 'saml:Attribute');
+ }
+
+}
diff --git a/lib/SAML2/XML/saml/AttributeValue.php b/lib/SAML2/XML/saml/AttributeValue.php
new file mode 100644
index 0000000..5351e99
--- /dev/null
+++ b/lib/SAML2/XML/saml/AttributeValue.php
@@ -0,0 +1,92 @@
+<?php
+
+/**
+ * Class representing an AttributeValue.
+ *
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class SAML2_XML_saml_AttributeValue {
+
+ /**
+ * The raw DOMElement representing this value.
+ *
+ * @var DOMElement
+ */
+ public $element;
+
+
+ /**
+ * Create an AttributeValue.
+ *
+ * @param mixed $value
+ * The value of this element.
+ * Can be one of:
+ * - string Create an attribute value with a simple string.
+ * - DOMElement(AttributeValue) Create an attribute value of the given DOMElement.
+ * - DOMElement Create an attribute value with the given DOMElement as a child.
+ */
+ public function __construct($value) {
+ assert('is_string($value) || $value instanceof DOMElement');
+
+ if (is_string($value)) {
+ $doc = new DOMDocument();
+ $this->element = $doc->createElementNS(SAML2_Const::NS_SAML, 'saml:AttributeValue');
+ $this->element->setAttributeNS(SAML2_Const::NS_XSI, 'xsi:type', 'xs:string');
+ $this->element->appendChild($doc->createTextNode($value));
+
+ /* Make sure that the xs-namespace is available in the AttributeValue (for xs:string). */
+ $this->element->setAttributeNS(SAML2_Const::NS_XS, 'xs:tmp', 'tmp');
+ $this->element->removeAttributeNS(SAML2_Const::NS_XS, 'tmp');
+
+ return;
+ }
+
+ if ($value->namespaceURI === SAML2_Const::NS_SAML && $value->localName === 'AttributeValue') {
+ $this->element = SAML2_Utils::copyElement($value);
+ return;
+ }
+
+ $doc = new DOMDocument();
+ $this->element = $doc->createElementNS(SAML2_Const::NS_SAML, 'saml:AttributeValue');
+ SAML2_Utils::copyElement($value, $this->element);
+ }
+
+
+ /**
+ * Append this attribute value to an element.
+ *
+ * @param DOMElement $parent The element we should append this attribute value to.
+ * @return DOMElement The generated AttributeValue element.
+ */
+ public function toXML(DOMElement $parent) {
+ assert('$this->element instanceof DOMElement');
+ assert('$this->element->namespaceURI === SAML2_Const::NS_SAML && $this->element->localName === "AttributeValue"');
+
+ $v = SAML2_Utils::copyElement($this->element, $parent);
+
+ return $v;
+ }
+
+
+ /**
+ * Convert this attribute value to a string.
+ *
+ * If this element contains XML data, that data vil be encoded as a string and returned.
+ *
+ * @return string This attribute value.
+ */
+ public function __toString() {
+ assert('$this->element instanceof DOMElement');
+
+ $doc = $this->element->ownerDocument;
+
+ $ret = '';
+ foreach ($this->element->childNodes as $c) {
+ $ret .= $doc->saveXML($c);
+ }
+
+ return $ret;
+ }
+
+}
diff --git a/lib/SAML2/XML/shibmd/Scope.php b/lib/SAML2/XML/shibmd/Scope.php
new file mode 100644
index 0000000..f095ba3
--- /dev/null
+++ b/lib/SAML2/XML/shibmd/Scope.php
@@ -0,0 +1,74 @@
+<?php
+
+/**
+ * Class which represents the Scope element found in Shibboleth metadata.
+ *
+ * @link https://spaces.internet2.edu/display/SHIB/ShibbolethMetadataProfile
+ * @package simpleSAMLphp
+ * @version $Id$
+ */
+class SAML2_XML_shibmd_Scope {
+
+ /**
+ * The namespace used for the Scope extension element.
+ */
+ const NS = 'urn:mace:shibboleth:metadata:1.0';
+
+
+ /**
+ * The scope.
+ *
+ * @var string
+ */
+ public $scope;
+
+ /**
+ * Whether this is a regexp scope.
+ *
+ * @var bool|NULL
+ */
+ public $regexp = NULL;
+
+
+ /**
+ * Create a Scope.
+ *
+ * @param DOMElement|NULL $xml The XML element we should load.
+ */
+ public function __construct(DOMElement $xml = NULL) {
+
+ if ($xml === NULL) {
+ return;
+ }
+
+ $this->scope = $xml->textContent;
+ $this->regexp = SAML2_Utils::parseBoolean($xml, 'regexp', NULL);
+ }
+
+
+ /**
+ * Convert this Scope to XML.
+ *
+ * @param DOMElement $parent The element we should append this Scope to.
+ */
+ public function toXML(DOMElement $parent) {
+ assert('is_string($this->scope)');
+ assert('is_bool($this->regexp) || is_null($this->regexp)');
+
+ $doc = $parent->ownerDocument;
+
+ $e = $doc->createElementNS(SAML2_XML_shibmd_Scope::NS, 'shibmd:Scope');
+ $parent->appendChild($e);
+
+ $e->appendChild($doc->createTextNode($this->scope));
+
+ if ($this->regexp === TRUE) {
+ $e->setAttribute('regexp', 'true');
+ } elseif ($this->regexp === FALSE) {
+ $e->setAttribute('regexp', 'false');
+ }
+
+ return $e;
+ }
+
+}