From f856329ac6703bb231c973a202a6842e1abbeb2c Mon Sep 17 00:00:00 2001 From: LDAV Date: Fri, 12 May 2023 10:34:33 +0200 Subject: [PATCH 1/4] Update Setup.php Add few correction to generate SPID compliant certificate --- setup/Setup.php | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/setup/Setup.php b/setup/Setup.php index 7f7450a..31f9ed8 100644 --- a/setup/Setup.php +++ b/setup/Setup.php @@ -834,7 +834,7 @@ public static function setup(Event $event) { $config['installDir'] . "/vendor/simplesamlphp/simplesamlphp/cert" ); echo $colors->getColoredString("\nConfiguring OpenSSL... ", "white"); - if (!file_exists('openssl.cnf')) { + if (!file_exists('spid-php-openssl.cnf')) { $openssl_config = fopen("spid-php-openssl.cnf", "w"); fwrite($openssl_config, "oid_section = spid_oids\n"); @@ -848,8 +848,12 @@ public static function setup(Event $event) { fwrite($openssl_config, "\n[ spid_oids ]\n"); //fwrite($openssl_config, "organizationIdentifier=2.5.4.97\n"); - fwrite($openssl_config, "spid-privatesector-SP=1.3.76.16.4.3.1\n"); - fwrite($openssl_config, "spid-publicsector-SP=1.3.76.16.4.2.1\n"); + fwrite($openssl_config, "agidcert=1.3.76.16.6\n"); + if($config['spIsPublicAdministration']) { + fwrite($openssl_config, "spid-publicsector-SP=1.3.76.16.4.2.1\n"); + } else { + fwrite($openssl_config, "spid-privatesector-SP=1.3.76.16.4.3.1\n"); + } fwrite($openssl_config, "uri=2.5.4.83\n"); fwrite($openssl_config, "\n[ dn ]\n"); @@ -862,7 +866,16 @@ public static function setup(Event $event) { //fwrite($openssl_config, "serialNumber=" . $config['spOrganizationCode'] . "\n"); fwrite($openssl_config, "\n[ req_ext ]\n"); - fwrite($openssl_config, "certificatePolicies = @spid_policies\n"); + fwrite($openssl_config, "basicConstraints=CA:FALSE\n"); + fwrite($openssl_config, "keyUsage=critical,digitalSignature,nonRepudiation\n"); + fwrite($openssl_config, "certificatePolicies=@agid_policies,@spid_policies\n"); + + fwrite($openssl_config, "\n[ agid_policies ]\n"); + fwrite($openssl_config, "policyIdentifier=agidcert\n"); + fwrite($openssl_config, "userNotice=@agidcert_notice\n"); + + fwrite($openssl_config, "\n[ agidcert_notice ]\n"); + fwrite($openssl_config, "explicitText=\"agIDcert\"\n"); fwrite($openssl_config, "\n[ spid_policies ]\n"); switch ($config['spIsPublicAdministration']) { @@ -878,7 +891,16 @@ public static function setup(Event $event) { die(); break; } - echo $colors->getColoredString("OK\n", "green"); + fwrite($openssl_config, "userNotice=@spid_notice\n"); + + fwrite($openssl_config, "\n[ spid_notice ]\n"); + if($config['spIsPublicAdministration']) { + fwrite($openssl_config, "explicitText=\"cert_SP_Pub\"\n"); + } else { + fwrite($openssl_config, "explicitText=\"cert_SP_Priv\"\n"); + } + + echo $colors->getColoredString("OK\n", "green"); } shell_exec( "openssl req -new -x509 -config spid-php-openssl.cnf -days 730 " . @@ -908,7 +930,7 @@ public static function setup(Event $event) { $config['installDir'] . "/vendor/simplesamlphp/simplesamlphp/cert" ); echo $colors->getColoredString("\nConfiguring OpenSSL... ", "white"); - if (!file_exists('openssl.cnf')) { + if (!file_exists('cie-php-openssl.cnf')) { $openssl_config = fopen("cie-php-openssl.cnf", "w"); fwrite($openssl_config, "oid_section = cie_oids\n"); From f9e0d00bd872637bc23fea186eaa0953fdd97cee Mon Sep 17 00:00:00 2001 From: Michele D'Amico Date: Mon, 3 Jul 2023 15:03:29 +0200 Subject: [PATCH 2/4] feat: add function getIdPList feat: add function getIdPList --- setup/sdk/spid-php.tpl | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/setup/sdk/spid-php.tpl b/setup/sdk/spid-php.tpl index 14fe2f2..0ae961e 100644 --- a/setup/sdk/spid-php.tpl +++ b/setup/sdk/spid-php.tpl @@ -20,6 +20,21 @@ {{IDPS}} } + public function getIdPList() { + include("vendor/simplesamlphp/simplesamlphp/metadata/saml20-idp-remote.php"); + + $list = []; + foreach($this->idps as $idp => $entity_id) { + array_push($list, array( + 'name' => $metadata[$entity_id]['name']['it'], + 'entity_id' => $entity_id, + 'code' => $idp, + 'logo_uri' => $metadata[$entity_id]['icon'] + )); + } + return $list; + } + public function isSPIDEnabled() { return self::SPID_ENABLED; } From 14a27f204e9b88e48dd759d67d48b357a5998841 Mon Sep 17 00:00:00 2001 From: Michele D'Amico Date: Mon, 3 Jul 2023 15:04:11 +0200 Subject: [PATCH 3/4] v.3.17.0 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index d8d2cfc..e59436f 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "config": { - "version": "3.16.0", + "version": "3.17.0", "allow-plugins": { "simplesamlphp/composer-module-installer": true } From 148aa494f6970c7873471c4b68d161e53c315852 Mon Sep 17 00:00:00 2001 From: damikael Date: Thu, 27 Jul 2023 17:48:53 +0200 Subject: [PATCH 4/4] fix: metadata spid namespaces --- .../saml2/src/SAML2/XML/md/ContactPerson.php | 12 +- .../src/SAML2/XML/md/EntityDescriptor.php | 551 ++++++++++++++++++ .../lib/SimpleSAML/Metadata/SAMLBuilder.php | 9 +- 3 files changed, 562 insertions(+), 10 deletions(-) create mode 100644 setup/simplesamlphp/saml2/src/SAML2/XML/md/EntityDescriptor.php diff --git a/setup/simplesamlphp/saml2/src/SAML2/XML/md/ContactPerson.php b/setup/simplesamlphp/saml2/src/SAML2/XML/md/ContactPerson.php index 59a52c9..0100c48 100644 --- a/setup/simplesamlphp/saml2/src/SAML2/XML/md/ContactPerson.php +++ b/setup/simplesamlphp/saml2/src/SAML2/XML/md/ContactPerson.php @@ -104,7 +104,7 @@ public function __construct(DOMElement $xml = null) if ($xml->hasAttribute('entityType')) { // SPID Entity Type (Avviso SPID n.19 v.4) if(substr($xml->getAttribute('entityType'), 0, 5)=='spid:') { - $this->setEntityType($xml->getAttribute('entityType'), 'spid'); + $this->setEntityType($xml->getAttribute('entityType'), 'spid:https://spid.gov.it/saml-extensions'); } else { $this->setEntityType($xml->getAttribute('entityType')); } @@ -219,13 +219,8 @@ public function setContactType(string $contactType) : void */ public function setEntityType(string $entityType, string $ns=null) : void { - if($ns!=null && $ns!='') { - $this->entityType = $ns.':'.$entityType; - $this->entityTypeNS = $ns; - } else { $this->entityType = $entityType; - $this->entityTypeNS = null; - } + $this->entityTypeNS = $ns; } @@ -457,7 +452,8 @@ public function toXML(DOMElement $parent) : DOMElement $e->setAttribute('contactType', $this->getContactType()); if ($this->entityType != null) { - $e->setAttribute($this->entityTypeNS . ($this->entityTypeNS? ':' : '') . 'entityType', $this->getEntityType()); + $attribute = ($this->entityTypeNS=='spid:https://spid.gov.it/saml-extensions')? 'spid:entityType' : 'entityType'; + $e->setAttribute($attribute, $this->entityType); } foreach ($this->getContactPersonAttributes() as $attr => $val) { diff --git a/setup/simplesamlphp/saml2/src/SAML2/XML/md/EntityDescriptor.php b/setup/simplesamlphp/saml2/src/SAML2/XML/md/EntityDescriptor.php new file mode 100644 index 0000000..fd41e52 --- /dev/null +++ b/setup/simplesamlphp/saml2/src/SAML2/XML/md/EntityDescriptor.php @@ -0,0 +1,551 @@ +hasAttribute('xmlns:spid')) { + $this->ns['spid'] = $xml->getAttribute('xmlns:spid'); + } + + 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 = Utils::xsDateTimeToTimestamp($xml->getAttribute('validUntil')); + } + if ($xml->hasAttribute('cacheDuration')) { + $this->cacheDuration = $xml->getAttribute('cacheDuration'); + } + + $this->Extensions = Extensions::getList($xml); + + foreach ($xml->childNodes as $node) { + if (!($node instanceof DOMElement)) { + continue; + } + + if ($node->namespaceURI !== Constants::NS_MD) { + continue; + } + + switch ($node->localName) { + case 'RoleDescriptor': + $this->RoleDescriptor[] = new UnknownRoleDescriptor($node); + break; + case 'IDPSSODescriptor': + $this->RoleDescriptor[] = new IDPSSODescriptor($node); + break; + case 'SPSSODescriptor': + $this->RoleDescriptor[] = new SPSSODescriptor($node); + break; + case 'AuthnAuthorityDescriptor': + $this->RoleDescriptor[] = new AuthnAuthorityDescriptor($node); + break; + case 'AttributeAuthorityDescriptor': + $this->RoleDescriptor[] = new AttributeAuthorityDescriptor($node); + break; + case 'PDPDescriptor': + $this->RoleDescriptor[] = new PDPDescriptor($node); + break; + case 'AffiliationDescriptor': + if ($this->AffiliationDescriptor !== null) { + throw new \Exception('More than one AffiliationDescriptor in the entity.'); + } + $this->AffiliationDescriptor = new AffiliationDescriptor($node); + break; + case 'Organization': + if ($this->Organization !== null) { + throw new \Exception('More than one Organization in the entity.'); + } + $this->Organization = new Organization($node); + break; + case 'ContactPerson': + $this->ContactPerson[] = new ContactPerson($node); + break; + case 'AdditionalMetadataLocation': + $this->AdditionalMetadataLocation[] = new AdditionalMetadataLocation($node); + break; + } + } + + 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.' + ); + } + } + + + /** + * Collect the value of the namespaces. + * + * @return string + */ + public function getNamespaces() : array + { + return $this->ns; + } + + + /** + * Set the value of the namespaces + * @param string $ns + * @param string $val + * @return void + */ + public function setNamespace(string $ns, string $val) : void + { + $this->ns[$ns] = $val; + } + + /** + * Collect the value of the entityID property. + * + * @return string + */ + public function getEntityID() : string + { + return $this->entityID; + } + + + /** + * Set the value of the entityID-property + * @param string $entityId + * @return void + */ + public function setEntityID(string $entityId) : void + { + $this->entityID = $entityId; + } + + + /** + * Collect the value of the ID property. + * + * @return string|null + */ + public function getID() : ?string + { + return $this->ID; + } + + + /** + * Set the value of the ID property. + * + * @param string|null $Id + * @return void + */ + public function setID(string $Id = null) : void + { + $this->ID = $Id; + } + + + /** + * Collect the value of the validUntil-property + * @return int|null + */ + public function getValidUntil() : ?int + { + return $this->validUntil; + } + + + /** + * Set the value of the validUntil-property + * @param int|null $validUntil + * @return void + */ + public function setValidUntil(int $validUntil = null) : void + { + $this->validUntil = $validUntil; + } + + + /** + * Collect the value of the cacheDuration-property + * @return string|null + */ + public function getCacheDuration() : ?string + { + return $this->cacheDuration; + } + + + /** + * Set the value of the cacheDuration-property + * @param string|null $cacheDuration + * @return void + */ + public function setCacheDuration(string $cacheDuration = null) : void + { + $this->cacheDuration = $cacheDuration; + } + + + /** + * Collect the value of the Extensions property. + * + * @return \SAML2\XML\Chunk[] + */ + public function getExtensions() : array + { + return $this->Extensions; + } + + + /** + * Set the value of the Extensions property. + * + * @param array $extensions + * @return void + */ + public function setExtensions(array $extensions) : void + { + $this->Extensions = $extensions; + } + + + /** + * Add an Extension. + * + * @param \SAML2\XML\Chunk $extensions The Extensions + * @return void + */ + public function addExtension(Extensions $extension) : void + { + $this->Extensions[] = $extension; + } + + + /** + * Collect the value of the RoleDescriptor property. + * + * @return \SAML2\XML\md\RoleDescriptor[] + */ + public function getRoleDescriptor() : array + { + return $this->RoleDescriptor; + } + + + /** + * Set the value of the RoleDescriptor property. + * + * @param \SAML2\XML\md\RoleDescriptor[] $roleDescriptor + * @return void + */ + public function setRoleDescriptor(array $roleDescriptor) : void + { + $this->RoleDescriptor = $roleDescriptor; + } + + + /** + * Add the value to the RoleDescriptor property. + * + * @param \SAML2\XML\md\RoleDescriptor $roleDescriptor + * @return void + */ + public function addRoleDescriptor(RoleDescriptor $roleDescriptor) : void + { + $this->RoleDescriptor[] = $roleDescriptor; + } + + + /** + * Collect the value of the AffiliationDescriptor property. + * + * @return \SAML2\XML\md\AffiliationDescriptor|null + */ + public function getAffiliationDescriptor() : ?AffiliationDescriptor + { + return $this->AffiliationDescriptor; + } + + + /** + * Set the value of the AffliationDescriptor property. + * + * @param \SAML2\XML\md\AffiliationDescriptor|null $affiliationDescriptor + * @return void + */ + public function setAffiliationDescriptor(AffiliationDescriptor $affiliationDescriptor = null) : void + { + $this->AffiliationDescriptor = $affiliationDescriptor; + } + + + /** + * Collect the value of the Organization property. + * + * @return \SAML2\XML\md\Organization|null + */ + public function getOrganization() : ?Organization + { + return $this->Organization; + } + + + /** + * Set the value of the Organization property. + * + * @param \SAML2\XML\md\Organization|null $organization + * @return void + */ + public function setOrganization(Organization $organization = null) : void + { + $this->Organization = $organization; + } + + + /** + * Collect the value of the ContactPerson property. + * + * @return \SAML2\XML\md\ContactPerson[] + */ + public function getContactPerson() : array + { + return $this->ContactPerson; + } + + + /** + * Set the value of the ContactPerson property. + * + * @param array $contactPerson + * @return void + */ + public function setContactPerson(array $contactPerson) : void + { + $this->ContactPerson = $contactPerson; + } + + + /** + * Add the value to the ContactPerson property. + * + * @param \SAML2\XML\md\ContactPerson $contactPerson + * @return void + */ + public function addContactPerson(ContactPerson $contactPerson) : void + { + $this->ContactPerson[] = $contactPerson; + } + + + /** + * Collect the value of the AdditionalMetadataLocation property. + * + * @return \SAML2\XML\md\AdditionalMetadataLocation[] + */ + public function getAdditionalMetadataLocation() : array + { + return $this->AdditionalMetadataLocation; + } + + + /** + * Set the value of the AdditionalMetadataLocation property. + * + * @param array $additionalMetadataLocation + * @return void + */ + public function setAdditionalMetadataLocation(array $additionalMetadataLocation) : void + { + $this->AdditionalMetadataLocation = $additionalMetadataLocation; + } + + + /** + * Add the value to the AdditionalMetadataLocation property. + * + * @param AdditionalMetadataLocation $additionalMetadataLocation + * @return void + */ + public function addAdditionalMetadataLocation(AdditionalMetadataLocation $additionalMetadataLocation) : void + { + $this->AdditionalMetadataLocation[] = $additionalMetadataLocation; + } + + + /** + * Create this EntityDescriptor. + * + * @param \DOMElement|null $parent The EntitiesDescriptor we should append this EntityDescriptor to. + * @return \DOMElement + */ + public function toXML(DOMElement $parent = null) : DOMElement + { + if (empty($this->entityID)) { + throw new \Exception('Cannot convert EntityDescriptor to XML without an EntityID set.'); + } + + if ($parent === null) { + $doc = DOMDocumentFactory::create(); + $e = $doc->createElementNS(Constants::NS_MD, 'md:EntityDescriptor'); + $doc->appendChild($e); + } else { + $e = $parent->ownerDocument->createElementNS(Constants::NS_MD, 'md:EntityDescriptor'); + $parent->appendChild($e); + } + + // set spid namespace if exists + if ($this->ns['spid'] !== null) { + $e->setAttribute('xmlns:spid', $this->ns['spid']); + } + + $e->setAttribute('entityID', $this->entityID); + + if ($this->ID !== null) { + $e->setAttribute('ID', $this->ID); + } + + if ($this->validUntil !== null) { + $e->setAttribute('validUntil', gmdate('Y-m-d\TH:i:s\Z', $this->validUntil)); + } + + if ($this->cacheDuration !== null) { + $e->setAttribute('cacheDuration', $this->cacheDuration); + } + + Extensions::addList($e, $this->Extensions); + + foreach ($this->RoleDescriptor as $n) { + $n->toXML($e); + } + + if ($this->AffiliationDescriptor !== null) { + $this->AffiliationDescriptor->toXML($e); + } + + if ($this->Organization !== null) { + $this->Organization->toXML($e); + } + + foreach ($this->ContactPerson as $cp) { + $cp->toXML($e); + } + + foreach ($this->AdditionalMetadataLocation as $n) { + $n->toXML($e); + } + + /** @var \DOMElement $child */ + $child = $e->firstChild; + $this->signElement($e, $child); + + return $e; + } +} diff --git a/setup/simplesamlphp/simplesamlphp/lib/SimpleSAML/Metadata/SAMLBuilder.php b/setup/simplesamlphp/simplesamlphp/lib/SimpleSAML/Metadata/SAMLBuilder.php index 04bb621..5d9715e 100644 --- a/setup/simplesamlphp/simplesamlphp/lib/SimpleSAML/Metadata/SAMLBuilder.php +++ b/setup/simplesamlphp/simplesamlphp/lib/SimpleSAML/Metadata/SAMLBuilder.php @@ -824,7 +824,8 @@ public function addContact($type, $details) $e->setContactType($type); if(isset($details['spidEntityType'])) { - $e->setEntityType($details['spidEntityType'], 'spid'); + $this->entityDescriptor->setNamespace('spid', 'https://spid.gov.it/saml-extensions'); + $e->setEntityType('spid:'.$details['spidEntityType'], 'spid:https://spid.gov.it/saml-extensions'); } $eexts = array(); @@ -896,8 +897,12 @@ public function addContact($type, $details) if (isset($details['extensions'])) { $ns = $details['extensions']['ns']; + if(substr($ns, 0, 5)=='spid:') { + $this->entityDescriptor->setNamespace('spid', 'https://spid.gov.it/saml-extensions'); + } + foreach($details['extensions']['elements'] as $e_key => $e_val) { - $ext_elem = $ext_dom->createElementNS($ns, $e_key, $e_val? $e_val : ''); + $ext_elem = $ext_dom->createElement($e_key, $e_val? $e_val : ''); $eexts[] = new \SAML2\XML\Chunk($ext_elem); } }