Skip to content

Commit

Permalink
Merge pull request #273 from silinternational/feature/metadata
Browse files Browse the repository at this point in the history
utilize SSP MetaDataStorageHandler
  • Loading branch information
briskt authored Jul 31, 2024
2 parents a3b643c + bfee226 commit 50f2c22
Show file tree
Hide file tree
Showing 16 changed files with 223 additions and 183 deletions.
2 changes: 1 addition & 1 deletion development/hub/config/authsources.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions development/idp-local/metadata/saml20-sp-remote.php
Original file line number Diff line number Diff line change
Expand Up @@ -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,
];
3 changes: 3 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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: .
Expand Down Expand Up @@ -226,6 +227,7 @@ services:
SECURE_COOKIE: "false"
SHOW_SAML_ERRORS: "true"
THEME_COLOR_SCHEME: "red-teal"
HUB_MODE: "false"

ssp-idp3.local:
build: .
Expand Down Expand Up @@ -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
Expand Down
67 changes: 63 additions & 4 deletions dockerbuild/run-spidplinks.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
14 changes: 3 additions & 11 deletions modules/sildisco/src/Auth/Process/AddIdp2NameId.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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])) {
Expand Down
16 changes: 4 additions & 12 deletions modules/sildisco/src/Auth/Process/LogUser.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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])) {
Expand Down
14 changes: 3 additions & 11 deletions modules/sildisco/src/Auth/Process/TagGroup.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down
75 changes: 58 additions & 17 deletions modules/sildisco/src/IdPDisco.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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);
}
Expand Down Expand Up @@ -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');

Expand Down Expand Up @@ -165,4 +154,56 @@ 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;
}

/**
* 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);
}
}
8 changes: 5 additions & 3 deletions modules/sildisco/tests/AddIdpTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -20,7 +25,6 @@ private static function getNameID($idp)
],
],
'Attributes' => [],
'metadataPath' => __DIR__ . '/fixtures/metadata/',
];
}

Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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'];
Expand Down
Loading

0 comments on commit 50f2c22

Please sign in to comment.