From 997f4f816aefa2781beabc670753e2f66da3005f Mon Sep 17 00:00:00 2001 From: briskt <3172830+briskt@users.noreply.github.com> Date: Sun, 28 Jul 2024 21:10:41 +0800 Subject: [PATCH 1/7] use SSP MetaDataStorageHandler in sildisco auth procs --- .../src/Auth/Process/AddIdp2NameId.php | 14 +++---------- modules/sildisco/src/Auth/Process/LogUser.php | 16 ++++----------- .../sildisco/src/Auth/Process/TagGroup.php | 14 +++---------- modules/sildisco/tests/AddIdpTest.php | 8 +++++--- modules/sildisco/tests/TagGroupTest.php | 10 ++++++---- .../sildisco/tests/fixtures/config/config.php | 6 ++++++ .../tests/fixtures/metadata/idp-bad-code.php | 12 ----------- .../tests/fixtures/metadata/idp-bare.php | 7 ------- .../tests/fixtures/metadata/idp-good.php | 8 -------- .../fixtures/metadata/saml20-idp-remote.php | 20 +++++++++++++++++++ 10 files changed, 47 insertions(+), 68 deletions(-) create mode 100644 modules/sildisco/tests/fixtures/config/config.php delete mode 100644 modules/sildisco/tests/fixtures/metadata/idp-bad-code.php delete mode 100644 modules/sildisco/tests/fixtures/metadata/idp-bare.php delete mode 100644 modules/sildisco/tests/fixtures/metadata/idp-good.php create mode 100644 modules/sildisco/tests/fixtures/metadata/saml20-idp-remote.php diff --git a/modules/sildisco/src/Auth/Process/AddIdp2NameId.php b/modules/sildisco/src/Auth/Process/AddIdp2NameId.php index 1ec92324..b41f01cc 100644 --- a/modules/sildisco/src/Auth/Process/AddIdp2NameId.php +++ b/modules/sildisco/src/Auth/Process/AddIdp2NameId.php @@ -3,10 +3,10 @@ namespace SimpleSAML\Module\sildisco\Auth\Process; use SAML2\XML\saml\NameID; -use Sil\SspUtils\Metadata; use SimpleSAML\Auth\ProcessingFilter; use SimpleSAML\Error; use SimpleSAML\Logger; +use SimpleSAML\Metadata\MetaDataStorageHandler; /** * Attribute filter for appending IDPNamespace to the NameID. @@ -134,16 +134,8 @@ public function process(array &$state): void return; } - // Get the potential IDPs from idp remote metadata - $metadataPath = __DIR__ . '/../../../../../metadata'; - - // If a unit test sends a different metadataPath, use it - if (isset($state['metadataPath'])) { - $metadataPath = $state['metadataPath']; - } - $idpEntries = Metadata::getIdpMetadataEntries($metadataPath); - - $idpEntry = $idpEntries[$samlIDP]; + $metadata = MetaDataStorageHandler::getMetadataHandler(); + $idpEntry = $metadata->getMetaData($samlIDP, 'saml20-idp-remote'); // The IDP metadata must have an IDPNamespace entry if (!isset($idpEntry[self::IDP_CODE_KEY])) { diff --git a/modules/sildisco/src/Auth/Process/LogUser.php b/modules/sildisco/src/Auth/Process/LogUser.php index c13f1c17..6d59643b 100644 --- a/modules/sildisco/src/Auth/Process/LogUser.php +++ b/modules/sildisco/src/Auth/Process/LogUser.php @@ -4,9 +4,9 @@ use Aws\DynamoDb\Marshaler; use Aws\Sdk; -use Sil\SspUtils\Metadata; use SimpleSAML\Auth\ProcessingFilter; use SimpleSAML\Logger; +use SimpleSAML\Metadata\MetaDataStorageHandler; /** * This Auth Proc logs information about each successful login to an AWS Dynamodb table. @@ -165,19 +165,11 @@ private function getIdp(array &$state) return 'No IDP available'; } - $samlIDP = $state[self::IDP_KEY]; - - // Get the potential IDPs from idp remote metadata - $metadataPath = __DIR__ . '/../../../../../metadata'; + $metadata = MetaDataStorageHandler::getMetadataHandler(); - // If a unit test sends a different metadataPath, use it - if (isset($state['metadataPath'])) { - $metadataPath = $state['metadataPath']; - } - $idpEntries = Metadata::getIdpMetadataEntries($metadataPath); + $samlIDP = $state[self::IDP_KEY]; - // Get the IDPNamespace or else just use the IDP's entity ID - $idpEntry = $idpEntries[$samlIDP]; + $idpEntry = $metadata->getMetaData($samlIDP, 'saml20-idp-remote'); // If the IDPNamespace entry is a string, use it if (isset($idpEntry[self::IDP_CODE_KEY]) && is_string($idpEntry[self::IDP_CODE_KEY])) { diff --git a/modules/sildisco/src/Auth/Process/TagGroup.php b/modules/sildisco/src/Auth/Process/TagGroup.php index 354244b0..791d76aa 100644 --- a/modules/sildisco/src/Auth/Process/TagGroup.php +++ b/modules/sildisco/src/Auth/Process/TagGroup.php @@ -2,8 +2,8 @@ namespace SimpleSAML\Module\sildisco\Auth\Process; -use Sil\SspUtils\Metadata; use SimpleSAML\Auth\ProcessingFilter; +use SimpleSAML\Metadata\MetaDataStorageHandler; /** * Attribute filter for prefixing group names @@ -50,19 +50,11 @@ public function process(array &$state): void return; } - // Get the potential IDPs from idp remote metadata - $metadataPath = __DIR__ . '/../../../../../metadata'; - - // If a unit test sends a different metadataPath, use it - if (isset($state['metadataPath'])) { - $metadataPath = $state['metadataPath']; - } - - $idpEntries = Metadata::getIdpMetadataEntries($metadataPath); + $metadata = MetaDataStorageHandler::getMetadataHandler(); $samlIDP = $state["saml:sp:IdP"]; - $idpEntry = $idpEntries[$samlIDP]; + $idpEntry = $metadata->getMetaData($samlIDP, 'saml20-idp-remote'); /* * If the IDP metadata has an IDPNamespace entry, use that value. Otherwise, diff --git a/modules/sildisco/tests/AddIdpTest.php b/modules/sildisco/tests/AddIdpTest.php index 686eb07e..5f99bfdb 100644 --- a/modules/sildisco/tests/AddIdpTest.php +++ b/modules/sildisco/tests/AddIdpTest.php @@ -3,10 +3,15 @@ use PHPUnit\Framework\TestCase; use SAML2\XML\saml\NameID; +use SimpleSAML\Configuration; use SimpleSAML\Module\sildisco\Auth\Process\AddIdp2NameId; class AddIdpTest extends TestCase { + public static function setUpBeforeClass(): void + { + Configuration::setConfigDir(__DIR__ . '/fixtures/config/'); + } private static function getNameID($idp) { @@ -20,7 +25,6 @@ private static function getNameID($idp) ], ], 'Attributes' => [], - 'metadataPath' => __DIR__ . '/fixtures/metadata/', ]; } @@ -91,7 +95,6 @@ public function testAddIdp2NameId_GoodString() 'saml:sp:IdP' => 'idp-good', 'saml:sp:NameID' => $nameID, 'Attributes' => [], - 'metadataPath' => __DIR__ . '/fixtures/metadata/', ]; $newNameID = new NameID(); @@ -119,7 +122,6 @@ public function testAddIdp2NameId_GoodArray() 'saml:sp:IdP' => 'idp-good', 'saml:sp:NameID' => $nameID, 'Attributes' => [], - 'metadataPath' => __DIR__ . '/fixtures/metadata/', ]; $newNameID = $state['saml:sp:NameID']; diff --git a/modules/sildisco/tests/TagGroupTest.php b/modules/sildisco/tests/TagGroupTest.php index c54b8c0a..c24f7357 100644 --- a/modules/sildisco/tests/TagGroupTest.php +++ b/modules/sildisco/tests/TagGroupTest.php @@ -1,10 +1,16 @@ ['ADMINS'], 'member' => ['ADMINS'], ], - 'metadataPath' => __DIR__ . '/fixtures/metadata/', ]; $expected = $request; @@ -55,7 +60,6 @@ public function testTagGroup_Member() "Attributes" => [ 'member' => ['ADMINS'], ], - 'metadataPath' => __DIR__ . '/fixtures/metadata/', ]; $expected = $request; @@ -76,7 +80,6 @@ public function testTagGroup_Oid() "Attributes" => [ 'urn:oid:2.5.4.31' => ['ADMINS'], ], - 'metadataPath' => __DIR__ . '/fixtures/metadata/', ]; $expected = $request; @@ -97,7 +100,6 @@ public function testTagGroup_IdpGood() "Attributes" => [ 'urn:oid:2.5.4.31' => ['ADMINS'], ], - 'metadataPath' => __DIR__ . '/fixtures/metadata/', ]; $expected = $request; diff --git a/modules/sildisco/tests/fixtures/config/config.php b/modules/sildisco/tests/fixtures/config/config.php new file mode 100644 index 00000000..950a88ce --- /dev/null +++ b/modules/sildisco/tests/fixtures/config/config.php @@ -0,0 +1,6 @@ + ['sildisco' => true], + 'metadatadir' => __DIR__ . '/../metadata', +]; diff --git a/modules/sildisco/tests/fixtures/metadata/idp-bad-code.php b/modules/sildisco/tests/fixtures/metadata/idp-bad-code.php deleted file mode 100644 index 8df2684c..00000000 --- a/modules/sildisco/tests/fixtures/metadata/idp-bad-code.php +++ /dev/null @@ -1,12 +0,0 @@ - [ - 'SingleSignOnService' => 'http://idp-empty/saml2/idp/SSOService.php', - 'IDPNamespace' => '', - ], - 'idp-bad' => [ - 'SingleSignOnService' => 'http://idp-bad/saml2/idp/SSOService.php', - 'IDPNamespace' => 'ba!d!', - ], -]; diff --git a/modules/sildisco/tests/fixtures/metadata/idp-bare.php b/modules/sildisco/tests/fixtures/metadata/idp-bare.php deleted file mode 100644 index b5a47975..00000000 --- a/modules/sildisco/tests/fixtures/metadata/idp-bare.php +++ /dev/null @@ -1,7 +0,0 @@ - [ - 'SingleSignOnService' => 'http://idp-bare/saml2/idp/SSOService.php', - ], -]; diff --git a/modules/sildisco/tests/fixtures/metadata/idp-good.php b/modules/sildisco/tests/fixtures/metadata/idp-good.php deleted file mode 100644 index 4cafa7c8..00000000 --- a/modules/sildisco/tests/fixtures/metadata/idp-good.php +++ /dev/null @@ -1,8 +0,0 @@ - [ - 'SingleSignOnService' => 'http://idp-bare/saml2/idp/SSOService.php', - 'IDPNamespace' => 'idpGood', - ], -]; diff --git a/modules/sildisco/tests/fixtures/metadata/saml20-idp-remote.php b/modules/sildisco/tests/fixtures/metadata/saml20-idp-remote.php new file mode 100644 index 00000000..5c76c187 --- /dev/null +++ b/modules/sildisco/tests/fixtures/metadata/saml20-idp-remote.php @@ -0,0 +1,20 @@ + 'http://idp-empty/saml2/idp/SSOService.php', + 'IDPNamespace' => '', +]; + +$metadata['idp-bad'] = [ + 'SingleSignOnService' => 'http://idp-bad/saml2/idp/SSOService.php', + 'IDPNamespace' => 'ba!d!', +]; + +$metadata['idp-bare'] = [ + 'SingleSignOnService' => 'http://idp-bare/saml2/idp/SSOService.php', +]; + +$metadata['idp-good'] = [ + 'SingleSignOnService' => 'http://idp-bare/saml2/idp/SSOService.php', + 'IDPNamespace' => 'idpGood', +]; From a03602a24de83493083a3e3152b8474473889813 Mon Sep 17 00:00:00 2001 From: briskt <3172830+briskt@users.noreply.github.com> Date: Sun, 28 Jul 2024 21:27:54 +0800 Subject: [PATCH 2/7] don't use SspUtils\Metadata in MetadataTest.php --- tests/MetadataTest.php | 141 ++++++++++++++--------------------------- 1 file changed, 48 insertions(+), 93 deletions(-) diff --git a/tests/MetadataTest.php b/tests/MetadataTest.php index 4786677c..57128261 100644 --- a/tests/MetadataTest.php +++ b/tests/MetadataTest.php @@ -7,8 +7,8 @@ use PHPUnit\Framework\TestCase; use Sil\PhpEnv\Env; use Sil\SspUtils\DiscoUtils; -use Sil\SspUtils\Metadata; use Sil\SspUtils\Utils; +use SimpleSAML\Metadata\MetaDataStorageHandler; class MetadataTest extends TestCase { @@ -25,49 +25,10 @@ class MetadataTest extends TestCase public $metadataPath = __DIR__ . '/../vendor/simplesamlphp/simplesamlphp/metadata'; - public function testLintTestMetadataFiles() - { - $spFiles = $this->getSpMetadataFiles(); - foreach ($spFiles as $file) { - $output = $returnVal = null; - exec('php -l ' . $file, $output, $returnVal); - $this->assertEquals( - 0, - $returnVal, - 'Lint test failed for file: ' . $file . '. Error: ' . print_r($output, true) - ); - } - - $idpFiles = $this->getIdPMetadataFiles(); - foreach ($idpFiles as $file) { - $output = $returnVal = null; - exec('php -l ' . $file, $output, $returnVal); - $this->assertEquals( - 0, - $returnVal, - 'Lint test failed for file: ' . $file . '. Error: ' . print_r($output, true) - ); - } - } - - public function testMetadataFilesReturnArrays() - { - $spFiles = $this->getSpMetadataFiles(); - foreach ($spFiles as $file) { - $returnVal = include $file; - $this->assertTrue(is_array($returnVal), 'Metadata file does not return array as expected. File: ' . $file); - } - - $idpFiles = $this->getIdPMetadataFiles(); - foreach ($idpFiles as $file) { - $returnVal = include $file; - $this->assertTrue(is_array($returnVal), 'Metadata file does not return array as expected. File: ' . $file); - } - } - public function testIDPRemoteMetadataIDPCode() { - $idpEntries = Metadata::getIdpMetadataEntries($this->metadataPath); + $metadata = MetaDataStorageHandler::getMetadataHandler(); + $idpEntries = $metadata->getList(); foreach ($idpEntries as $entityId => $entry) { $this->assertTrue(isset($entry[self::IdpCode]), 'Metadata entry does not ' . @@ -92,7 +53,8 @@ public function testIDPRemoteMetadataBadSPList() $badIdps = []; - $idpEntries = Metadata::getIdpMetadataEntries($this->metadataPath); + $metadata = MetaDataStorageHandler::getMetadataHandler(); + $idpEntries = $metadata->getList(); $spListKey = Utils::SP_LIST_KEY; foreach ($idpEntries as $entityId => $entry) { @@ -117,7 +79,8 @@ public function testIDPRemoteMetadataMissingLogoCaption() $badIdps = []; - $idpEntries = Metadata::getIdpMetadataEntries($this->metadataPath); + $metadata = MetaDataStorageHandler::getMetadataHandler(); + $idpEntries = $metadata->getList(); foreach ($idpEntries as $entityId => $entry) { if (!isset($entry[self::LogoCaptionKey])) { @@ -140,11 +103,12 @@ public function testIDPRemoteMetadataBadSPListEntry() return; } - $spEntries = Metadata::getSpMetadataEntries($this->metadataPath); + $metadata = MetaDataStorageHandler::getMetadataHandler(); + $spEntries = $metadata->getList('saml20-sp-remote'); $badSps = []; - $idpEntries = Metadata::getIdpMetadataEntries($this->metadataPath); + $idpEntries = $metadata->getList(); $spListKey = Utils::SP_LIST_KEY; foreach ($idpEntries as $entityId => $entry) { @@ -166,7 +130,8 @@ public function testIDPRemoteMetadataBadSPListEntry() public function testIDPRemoteMetadataNoDuplicateIDPCode() { - $idpEntries = Metadata::getIdpMetadataEntries($this->metadataPath); + $metadata = MetaDataStorageHandler::getMetadataHandler(); + $idpEntries = $metadata->getList(); $codes = []; foreach ($idpEntries as $entityId => $entry) { @@ -179,29 +144,24 @@ public function testIDPRemoteMetadataNoDuplicateIDPCode() public function testMetadataNoDuplicateEntities() { + $metadata = MetaDataStorageHandler::getMetadataHandler(); + $spEntries = $metadata->getList('saml20-sp-remote'); $entities = []; - $spFiles = $this->getSpMetadataFiles(); - foreach ($spFiles as $file) { - $returnVal = include $file; - foreach ($returnVal as $entityId => $entity) { - $this->assertFalse( - in_array($entityId, $entities), - 'Duplicate entity id found in metadata file: ' . $file . '. Entity ID: ' . $entityId - ); - $entities[] = $entityId; - } + foreach ($spEntries as $entityId => $entity) { + $this->assertFalse( + in_array($entityId, $entities), + 'Duplicate SP entityId found: ' . $entityId + ); + $entities[] = $entityId; } - $idpFiles = $this->getIdPMetadataFiles(); - foreach ($idpFiles as $file) { - $returnVal = include $file; - foreach ($returnVal as $entityId => $entity) { - $this->assertFalse( - in_array($entityId, $entities), - 'Duplicate entity id found in metadata file: ' . $file . '. Entity ID: ' . $entityId - ); - $entities[] = $entityId; - } + $idpEntries = $metadata->getList(); + foreach ($idpEntries as $entityId => $entity) { + $this->assertFalse( + in_array($entityId, $entities), + 'Duplicate IdP entityId found: ' . $entityId + ); + $entities[] = $entityId; } } @@ -213,7 +173,8 @@ public function testMetadataNoSpsWithoutAnIdp() return; } - $spEntries = Metadata::getSpMetadataEntries($this->metadataPath); + $metadata = MetaDataStorageHandler::getMetadataHandler(); + $spEntries = $metadata->getList('saml20-sp-remote'); $badSps = []; foreach ($spEntries as $spEntityId => $spEntry) { @@ -234,7 +195,8 @@ public function testMetadataNoSpsWithoutAnIdp() public function testMetadataBadIdpName() { - $idpEntries = Metadata::getIdpMetadataEntries($this->metadataPath); + $metadata = MetaDataStorageHandler::getMetadataHandler(); + $idpEntries = $metadata->getList(); $badNames = []; @@ -251,7 +213,8 @@ public function testMetadataBadIdpName() public function testMetadataMissingLogoURL() { - $idpEntries = Metadata::getIdpMetadataEntries($this->metadataPath); + $metadata = MetaDataStorageHandler::getMetadataHandler(); + $idpEntries = $metadata->getList(); $badLogos = []; @@ -269,8 +232,9 @@ public function testMetadataMissingLogoURL() public function testMetadataSPWithBadIDPList() { $idpListKey = Utils::IDP_LIST_KEY; - $idpEntries = Metadata::getIdpMetadataEntries($this->metadataPath); - $spEntries = Metadata::getSpMetadataEntries($this->metadataPath); + $metadata = MetaDataStorageHandler::getMetadataHandler(); + $idpEntries = $metadata->getList(); + $spEntries = $metadata->getList('saml20-sp-remote'); $badSps = []; @@ -301,7 +265,8 @@ public function testMetadataSPWithNoIDPList() return; } $idpListKey = Utils::IDP_LIST_KEY; - $spEntries = Metadata::getSpMetadataEntries($this->metadataPath); + $metadata = MetaDataStorageHandler::getMetadataHandler(); + $spEntries = $metadata->getList('saml20-sp-remote'); $badSps = []; @@ -324,7 +289,8 @@ public function testMetadataSPWithNoName() return; } - $spEntries = Metadata::getSpMetadataEntries($this->metadataPath); + $metadata = MetaDataStorageHandler::getMetadataHandler(); + $spEntries = $metadata->getList('saml20-sp-remote'); $badSps = []; @@ -341,7 +307,8 @@ public function testMetadataSPWithNoName() public function testMetadataCerts() { - $spEntries = Metadata::getSpMetadataEntries($this->metadataPath); + $metadata = MetaDataStorageHandler::getMetadataHandler(); + $spEntries = $metadata->getList('saml20-sp-remote'); $badSps = []; @@ -365,7 +332,8 @@ public function testMetadataCerts() public function testMetadataSignResponse() { // $this->markTestSkipped('Disabled for testing/verification'); - $spEntries = Metadata::getSpMetadataEntries($this->metadataPath); + $metadata = MetaDataStorageHandler::getMetadataHandler(); + $spEntries = $metadata->getList('saml20-sp-remote'); $badSps = []; $skippedSps = []; @@ -395,7 +363,8 @@ public function testMetadataSignResponse() public function testMetadataSignAssertion() { // $this->markTestSkipped('Disabled for testing/verification'); - $spEntries = Metadata::getSpMetadataEntries($this->metadataPath); + $metadata = MetaDataStorageHandler::getMetadataHandler(); + $spEntries = $metadata->getList('saml20-sp-remote'); $badSps = []; $skippedSps = []; @@ -425,7 +394,8 @@ public function testMetadataSignAssertion() public function testMetadataEncryption() { // $this->markTestSkipped('Wait until we require encryption.'); - $spEntries = Metadata::getSpMetadataEntries($this->metadataPath); + $metadata = MetaDataStorageHandler::getMetadataHandler(); + $spEntries = $metadata->getList('saml20-sp-remote'); $badSps = []; $skippedSps = []; @@ -450,19 +420,4 @@ public function testMetadataEncryption() ' metadata entry set ... ' . var_export($skippedSps, True)); } } - - public function getSpMetadataFiles() - { - return $this->getFileList('sp'); - } - - public function getIdPMetadataFiles() - { - return $this->getFileList('idp'); - } - - public function getFileList($prefix) - { - return Metadata::getMetadataFiles($this->metadataPath, $prefix); - } } From 4a3073e5883d1a47b65fe7e0dd6e8e235b51ebcb Mon Sep 17 00:00:00 2001 From: briskt <3172830+briskt@users.noreply.github.com> Date: Mon, 29 Jul 2024 07:22:17 +0800 Subject: [PATCH 3/7] fix metadata tests --- development/hub/config/authsources.php | 2 +- development/idp-local/metadata/saml20-sp-remote.php | 1 + docker-compose.yml | 3 +++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/development/hub/config/authsources.php b/development/hub/config/authsources.php index c3a20cbf..fe1b5130 100644 --- a/development/hub/config/authsources.php +++ b/development/hub/config/authsources.php @@ -13,7 +13,7 @@ // The URL to the discovery service. // Can be NULL/unset, in which case a builtin discovery service will be used. 'discoURL' => 'http://ssp-hub.local/module.php/sildisco/disco.php', - + 'privatekey' => 'saml.pem', ], // This is a authentication source which handles admin authentication. diff --git a/development/idp-local/metadata/saml20-sp-remote.php b/development/idp-local/metadata/saml20-sp-remote.php index 4720d9ad..7e46ff44 100644 --- a/development/idp-local/metadata/saml20-sp-remote.php +++ b/development/idp-local/metadata/saml20-sp-remote.php @@ -14,4 +14,5 @@ 'AssertionConsumerService' => 'http://ssp-hub.local/module.php/saml/sp/saml2-acs.php/hub-discovery', 'SingleLogoutService' => 'http://ssp-hub.local/module.php/saml/sp/saml2-logout.php/hub-discovery', 'certData' => 'MIIDzzCCAregAwIBAgIJANuvVcQPANecMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJOQzEPMA0GA1UEBwwGV2F4aGF3MQwwCgYDVQQKDANTSUwxDTALBgNVBAsMBEdUSVMxDjAMBgNVBAMMBVN0ZXZlMSQwIgYJKoZIhvcNAQkBFhVzdGV2ZV9iYWd3ZWxsQHNpbC5vcmcwHhcNMTYxMDE3MTIzMTEyWhcNMjYxMDE3MTIzMTEyWjB+MQswCQYDVQQGEwJVUzELMAkGA1UECAwCTkMxDzANBgNVBAcMBldheGhhdzEMMAoGA1UECgwDU0lMMQ0wCwYDVQQLDARHVElTMQ4wDAYDVQQDDAVTdGV2ZTEkMCIGCSqGSIb3DQEJARYVc3RldmVfYmFnd2VsbEBzaWwub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxAimEkw4Teyf/gZelL7OuQYg/JbDIKHPXJhLPBm/HK6pM5ZZKydVXTdMgMqkl4xK+xZ2CnkozsUiMLhAuWBsX9Dcz1M4SkPRwk4puFhXzsp7fKIVP43zUhF7p2TmbernrrIQHjg6PuegKmCGyiKUpukcYvf2RXNwHwJx+Uq0zLP4PgBSrQ2t1eKZ1jQ+noBb1NqOuy969WRYmN4EmjXDuJB9d+b3GwtbZToWgiFxFjd/NN9BFJXZEaLzRj5LAq5bu2vPPDZDarHFMRUzVJ91eafoaz6zpR1iUGj9zR+y2sUPxD/fJMZ+4AHWA2LOrTBBIuuWbp96yvcJ4WjmlfhcFQIDAQABo1AwTjAdBgNVHQ4EFgQUkJFAMJdr2lXsuezS6pDXHnmJspMwHwYDVR0jBBgwFoAUkJFAMJdr2lXsuezS6pDXHnmJspMwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAOEPbchaUr45L5i+ueookevsABYnltwJZ4rYJbF9VURPcEhB6JxTMZqb4s113ftHvVYfoAfLYZ9swETaHL+esx41yAebf0kWpQ3f63S5F2FcrTj+HP0XsvW/EDrvaTKM9jnKPNmbXrpq06eaUZfkVL0TAUsxYTKkttTSTiESEzp5wzYyhp7l3kpHhEvGOlh5suYjnZ2HN0uxscCR6PS47H6TMMEZuG032DWDC016/JniWvERtpf4Yw26V+I9xevp2E2MPcZne31Pe3sCh4Wpe4cV/SCFqZHlpnH96ncz4F+KvmmhbEx5VPhQSJNFIWEvI86k+lTNQOqj6YVvGvq95LQ==', + 'assertion.encryption' => true, ]; diff --git a/docker-compose.yml b/docker-compose.yml index 16108e9f..752cf380 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -179,6 +179,7 @@ services: BASE_URL_PATH: "http://ssp-idp1.local/" # change this to "http://ssp-idp1.local:8085" for manual browser testing HELP_CENTER_URL: "https://example.org/help" THEME_COLOR_SCHEME: "blue_grey-teal" + HUB_MODE: "false" ssp-idp2.local: build: . @@ -226,6 +227,7 @@ services: SECURE_COOKIE: "false" SHOW_SAML_ERRORS: "true" THEME_COLOR_SCHEME: "red-teal" + HUB_MODE: "false" ssp-idp3.local: build: . @@ -258,6 +260,7 @@ services: SECURE_COOKIE: "false" SHOW_SAML_ERRORS: "true" THEME_COLOR_SCHEME: "orange-light_blue" + HUB_MODE: "false" ssp-sp1.local: image: silintl/ssp-base:9.3.0 From 9c4a5abe61d1cc17560380e81b5c11f0ab4690ca Mon Sep 17 00:00:00 2001 From: briskt <3172830+briskt@users.noreply.github.com> Date: Mon, 29 Jul 2024 08:09:58 +0800 Subject: [PATCH 4/7] use MetaDataStorageHandler in IdPDisco.php --- modules/sildisco/src/IdPDisco.php | 60 ++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 17 deletions(-) diff --git a/modules/sildisco/src/IdPDisco.php b/modules/sildisco/src/IdPDisco.php index c4e26e45..2bc190a7 100644 --- a/modules/sildisco/src/IdPDisco.php +++ b/modules/sildisco/src/IdPDisco.php @@ -3,11 +3,12 @@ namespace SimpleSAML\Module\sildisco; use Sil\SspUtils\AnnouncementUtils; -use Sil\SspUtils\DiscoUtils; -use Sil\SspUtils\Metadata; +use Sil\SspUtils\Utils; use SimpleSAML\Auth; +use SimpleSAML\Error\MetadataNotFound; use SimpleSAML\Error\NoState; use SimpleSAML\Logger; +use SimpleSAML\Metadata\MetaDataStorageHandler; use SimpleSAML\Utils\HTTP; use SimpleSAML\XHTML\IdPDisco as SSPIdPDisco; use SimpleSAML\XHTML\Template; @@ -35,12 +36,6 @@ protected function log(string $message): void Logger::info('SildiscoIdPDisco.' . $this->instance . ': ' . $message); } - /* Path to the folder with the SP and IdP metadata */ - private function getMetadataPath() - { - return __DIR__ . '/../../../metadata/'; - } - /** * @throws NoState * @throws Exception @@ -66,12 +61,7 @@ private function getSPEntityIDAndReducedIdpList(): array throw new Exception('empty SP entityID'); } - $idpList = DiscoUtils::getReducedIdpList( - $idpList, - $this->getMetadataPath(), - $spEntityId - ); - + $idpList = self::getReducedIdpList($idpList, $spEntityId); return array($spEntityId, $idpList); } @@ -103,9 +93,8 @@ public function handleRequest(): void } } - // Get the SP metadata entry - $spEntries = Metadata::getSpMetadataEntries($this->getMetadataPath()); - $sp = $spEntries[$spEntityId]; + $metadata = MetaDataStorageHandler::getMetadataHandler(); + $sp = $metadata->getMetaData($spEntityId, 'saml20-sp-remote'); $t = new Template($this->config, 'selectidp-links', 'disco'); @@ -165,4 +154,41 @@ protected function validateIdP(?string $idp): ?string // the entity id wasn't valid return null; } + + /** + * Takes the original IDP List and reduces it down to the ones the current SP is meant to see. + * The relevant entries in saml20-idp-remote.php would be ... + * - 'excludeByDefault' (boolean), which when set to True would keep this idp from being + * shown to SP's that don't explicitly include it in the 'IDPList' entry of their metadata. + * - 'SPList' (array), which when set would only allow this idp to be shown + * to SPs whose entity_id is included in this array. + * + * @param array $idpList + * @param string $spEntityId - the current SP's entity id + * @return array of a subset of the original $startSources. + * @throws MetadataNotFound + */ + public static function getReducedIdpList(array $idpList, string $spEntityId): array + { + $metadata = MetaDataStorageHandler::getMetadataHandler(); + $spMetadata = $metadata->getMetaData($spEntityId, 'saml20-sp-remote'); + + $reducedIdpList = []; + + $idpListForSp = []; // The list of IDP's this SP wants to know about + if (array_key_exists(Utils::IDP_LIST_KEY, $spMetadata)) { + $idpListForSp = $spMetadata[Utils::IDP_LIST_KEY]; + } + + foreach ($idpList as $idpEntityId => $idpMdEntry) { + if (Utils::isIdpValidForSp($idpEntityId, + $idpMdEntry, + $spEntityId, + $idpListForSp) + ) { + $reducedIdpList[$idpEntityId] = $idpMdEntry; + } + } + return $reducedIdpList; + } } From 19e100dece16f57ce2dc1f3f9e5e87f7bfe8990a Mon Sep 17 00:00:00 2001 From: briskt <3172830+briskt@users.noreply.github.com> Date: Mon, 29 Jul 2024 08:49:08 +0800 Subject: [PATCH 5/7] use MetaDataStorageHandler in run-spidplinks.php --- dockerbuild/run-spidplinks.php | 67 +++++++++++++++++++++++++++++-- modules/sildisco/src/IdPDisco.php | 15 +++++++ tests/MetadataTest.php | 7 +--- 3 files changed, 80 insertions(+), 9 deletions(-) diff --git a/dockerbuild/run-spidplinks.php b/dockerbuild/run-spidplinks.php index 82e3f723..2a6e0835 100644 --- a/dockerbuild/run-spidplinks.php +++ b/dockerbuild/run-spidplinks.php @@ -2,10 +2,69 @@ include "/data/vendor/autoload.php"; -use Sil\SspUtils\DiscoUtils; +use SimpleSAML\Metadata\MetaDataStorageHandler; +use SimpleSAML\Module\sildisco\IdPDisco; -$mdPath = "/data/vendor/simplesamlphp/simplesamlphp/metadata"; +echo listAllSpIdpLinks(); -$results = DiscoUtils::listAllSpIdpLinks($mdPath, "nothtml"); +/** + * Returns a nested array of all the IdP's that are available to each SP + * + * @return array ["sp1" => ["idp1", ...], ...]] + */ +function getSpIdpLinks(): array +{ + $links = []; + $metadata = MetaDataStorageHandler::getMetadataHandler(); + $spEntries = $metadata->getList('saml20-sp-remote'); -echo $results["text"]; + foreach ($spEntries as $spEntityId => $spEntry) { + $idpList = IdPDisco::getIdpsForSp($spEntityId); + $links[$spEntityId] = array_keys($idpList); + } + return $links; +} + +/** + * Returns a nested array of all the SPs that are allowed to use each IdP + * and all the IdPs that are available to each SP + */ +function listAllSpIdpLinks(): string +{ + $spLinks = getSpIdpLinks(); + $idpLinks = []; + + // transpose the SP-based array for the IdP-based array + foreach ($spLinks as $nextSp => $idps) { + foreach ($idps as $nextIdp) { + if (!isset($idpLinks[$nextIdp])) { + $idpLinks[$nextIdp] = []; + } + $idpLinks[$nextIdp][] = $nextSp; + } + } + + $output = PHP_EOL . "These IdPs are available to the corresponding SPs" . PHP_EOL; + + foreach ($idpLinks as $idpEntityId => $spList) { + $output .= ' ' . $idpEntityId . ' is available to ...' . PHP_EOL; + foreach ($spList as $nextSp) { + $output .= ' ' . $nextSp . PHP_EOL; + } + $output .= '-----------' . PHP_EOL; + $output .= PHP_EOL; + } + + $output .= PHP_EOL . "These SPs may use the corresponding IdPs" . PHP_EOL; + + foreach ($spLinks as $spEntityId => $idpList) { + $output .= ' ' . $spEntityId . ' may use ... ' . PHP_EOL; + foreach ($idpList as $nextIdp) { + $output .= ' ' . $nextIdp . PHP_EOL; + } + $output .= '-----------' . PHP_EOL; + $output .= PHP_EOL; + } + + return $output; +} diff --git a/modules/sildisco/src/IdPDisco.php b/modules/sildisco/src/IdPDisco.php index 2bc190a7..97eccd86 100644 --- a/modules/sildisco/src/IdPDisco.php +++ b/modules/sildisco/src/IdPDisco.php @@ -191,4 +191,19 @@ public static function getReducedIdpList(array $idpList, string $spEntityId): ar } return $reducedIdpList; } + + /** + * Takes the original idp entries and reduces them down to the ones the current SP is meant to see. + * + * @param string $spEntityId + * @return array + * @throws MetadataNotFound + */ + public static function getIdpsForSp(string $spEntityId): array + { + $metadata = MetaDataStorageHandler::getMetadataHandler(); + $idpEntries = $metadata->getList(); + + return self::getReducedIdpList($idpEntries, $spEntityId); + } } diff --git a/tests/MetadataTest.php b/tests/MetadataTest.php index 57128261..15d05710 100644 --- a/tests/MetadataTest.php +++ b/tests/MetadataTest.php @@ -6,9 +6,9 @@ use PHPUnit\Framework\TestCase; use Sil\PhpEnv\Env; -use Sil\SspUtils\DiscoUtils; use Sil\SspUtils\Utils; use SimpleSAML\Metadata\MetaDataStorageHandler; +use SimpleSAML\Module\sildisco\IdPDisco; class MetadataTest extends TestCase { @@ -178,10 +178,7 @@ public function testMetadataNoSpsWithoutAnIdp() $badSps = []; foreach ($spEntries as $spEntityId => $spEntry) { - $results = DiscoUtils::getIdpsForSp( - $spEntityId, - $this->metadataPath - ); + $results = IdPDisco::getIdpsForSp($spEntityId); if (empty($results)) { $badSps[] = $spEntityId; From 844f542144cb07f5652ee7e7963ec357abe01fd6 Mon Sep 17 00:00:00 2001 From: briskt <3172830+briskt@users.noreply.github.com> Date: Tue, 30 Jul 2024 11:27:52 +0800 Subject: [PATCH 6/7] bypass ssp-base config.php for metadata "tests" --- tests/MetadataTest.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/MetadataTest.php b/tests/MetadataTest.php index 15d05710..11b0a565 100644 --- a/tests/MetadataTest.php +++ b/tests/MetadataTest.php @@ -7,6 +7,7 @@ use PHPUnit\Framework\TestCase; use Sil\PhpEnv\Env; use Sil\SspUtils\Utils; +use SimpleSAML\Configuration; use SimpleSAML\Metadata\MetaDataStorageHandler; use SimpleSAML\Module\sildisco\IdPDisco; @@ -25,6 +26,12 @@ class MetadataTest extends TestCase public $metadataPath = __DIR__ . '/../vendor/simplesamlphp/simplesamlphp/metadata'; + public static function setUpBeforeClass(): void + { + // use default configuration to bypass the ssp-base config file that has required environment variables + Configuration::setPreLoadedConfig(Configuration::loadFromArray([])); + } + public function testIDPRemoteMetadataIDPCode() { $metadata = MetaDataStorageHandler::getMetadataHandler(); From 9ee32d34bc8d909dd829eba686f301b9ec7d883a Mon Sep 17 00:00:00 2001 From: briskt <3172830+briskt@users.noreply.github.com> Date: Tue, 30 Jul 2024 11:36:24 +0800 Subject: [PATCH 7/7] enable sildisco module to gain access to getIdpsForSp method --- tests/MetadataTest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/MetadataTest.php b/tests/MetadataTest.php index 11b0a565..0eeca0a5 100644 --- a/tests/MetadataTest.php +++ b/tests/MetadataTest.php @@ -28,8 +28,10 @@ class MetadataTest extends TestCase public static function setUpBeforeClass(): void { - // use default configuration to bypass the ssp-base config file that has required environment variables - Configuration::setPreLoadedConfig(Configuration::loadFromArray([])); + // override configuration to bypass the ssp-base config file that has required environment variables + Configuration::setPreLoadedConfig(Configuration::loadFromArray([ + 'module.enable' => ['sildisco' => true], // for IdPDisco::getIdpsForSp utility function + ])); } public function testIDPRemoteMetadataIDPCode()