Skip to content

Instantly share code, notes, and snippets.

@pradtke
Last active December 8, 2015 23:28
Embed
What would you like to do?
Registration Authority Filter for Simple Saml Php 1.13.2

This patch is a back port of more advanced metadata filtering for SimpleSamlPhp. The patch has been tested against SSP 1.13.2

Apply patch

# Download patch to /tmp/filter-metaloader.patch
# cd $SSP_INSTALL;  # example: cd /var/simplesamlphp
patch -p1 < /tmp/filter-metaloader.patch

Use new filters

The patch allows SSP to fitler metadata based on a function, and predefines functions for filtering by registration authority

Edit config/config-metarefresh.php and add filterFactory and filterFactoryArgs

'incommon' => array(
    'cron'  => array('frequent'),
    'sources'   => array(
        array(
            'src'   => 'http://md.incommon.org/InCommon/InCommon-metadata.xml',
            'validateFingerprint' => '7D:B4:BB:28:D3:D5:C8:52:E0:80:B3:62:43:2A:AF:34:B2:A6:0E:DD',
            // We already have a ProtectNetwork entry in the guest options
            'blacklist' => array(
                'urn:mace:incommon:idp.protectnetwork.org',
            ),
            // Only accept entities registered by incommon
            'filterFactory' => 'sspmod_metarefresh_CommonFilters::registeredAuthorityFilterFactory',
            'filterFactoryArgs' => array('https://incommon.org'),
        ),
    ),
    'outputDir' =>  'metadata/metarefresh/incommon',
    'outputFormat'  => 'flatfile',
),

Log Output

The filter produces LOG output like:

simplesamlphp INFO [2080b1e176] Skipping "$ENTITY_ID" - filtered by custom filter.

Memory and Execution time

You are likely applying this patch to handle metadata aggregates that contain eduGain data. These larger files also require more memory for processing, so don't forget to increase memory_limit and max_execution_time

Warnings

The Pull Request to get these changes into the next release of SimpleSamlPhp has not been reviewed. This means filter names and arguments may change. It means SSP 1.14 may not have these changes and may need to be patched.

diff --git a/lib/SimpleSAML/Metadata/SAMLParser.php b/lib/SimpleSAML/Metadata/SAMLParser.php
index 41b06a6..927a212 100644
--- a/lib/SimpleSAML/Metadata/SAMLParser.php
+++ b/lib/SimpleSAML/Metadata/SAMLParser.php
@@ -100,6 +100,10 @@ class SimpleSAML_Metadata_SAMLParser {
private $uiInfo;
private $discoHints;
+ /**
+ * @var array
+ */
+ private $registrationInfo;
/**
* This is an array of elements that may be used to validate this element.
@@ -144,6 +148,7 @@ class SimpleSAML_Metadata_SAMLParser {
$this->scopes = $ext['scope'];
$this->tags = $ext['tags'];
$this->entityAttributes = $ext['EntityAttributes'];
+ $this->registrationInfo = $ext['RegistrationInfo'];
/* Look over the RoleDescriptors. */
foreach ($entityElement->RoleDescriptor as $child) {
@@ -424,7 +429,11 @@ class SimpleSAML_Metadata_SAMLParser {
if (!empty($tags)) {
$metadata['tags'] = $tags;
}
-
+
+ if (!empty($this->registrationInfo)) {
+ $metadata['RegistrationInfo'] = $this->registrationInfo;
+ }
+
if (!empty($this->entityAttributes)) {
$metadata['EntityAttributes'] = $this->entityAttributes;
}
@@ -900,6 +909,7 @@ class SimpleSAML_Metadata_SAMLParser {
'scope' => array(),
'tags' => array(),
'EntityAttributes' => array(),
+ 'RegistrationInfo' => array(),
'UIInfo' => array(),
'DiscoHints' => array(),
);
@@ -914,7 +924,9 @@ class SimpleSAML_Metadata_SAMLParser {
// Entity Attributes are only allowed at entity level extensions
// and not at RoleDescriptor level
if ($element instanceof SAML2_XML_md_EntityDescriptor) {
-
+ if ($e instanceof SAML2_XML_mdrpi_RegistrationInfo) {
+ $ret['RegistrationInfo']['registrationAuthority'] = $e->registrationAuthority;
+ }
if ($e instanceof SAML2_XML_mdattr_EntityAttributes && !empty($e->children)) {
foreach($e->children AS $attr) {
diff --git a/modules/metarefresh/lib/CommonFilters.php b/modules/metarefresh/lib/CommonFilters.php
new file mode 100644
index 0000000..e18b9d5
--- /dev/null
+++ b/modules/metarefresh/lib/CommonFilters.php
@@ -0,0 +1,51 @@
+<?php
+/*
+ * Filter callbacks and callback factories that are useful to most SSP users
+ */
+class sspmod_metarefresh_CommonFilters {
+
+
+ /**
+ * @param $authority The registration authority the entity should match
+ * @return Closure A closure that will return true if called with an entity registered by $authority
+ */
+ public static function registeredAuthorityFilterFactory($authority) {
+ return function(SimpleSAML_Metadata_SAMLParser $entityDesc) use ($authority) {
+ $metaData = sspmod_metarefresh_CommonFilters::getMetadata($entityDesc);
+ return isset($metaData['RegistrationInfo']['registrationAuthority']) && $metaData['RegistrationInfo']['registrationAuthority'] === $authority;
+ };
+ }
+
+ /**
+ * @param $name The name of the entity attribute to check
+ * @param $value The value that the entity attribute should contain
+ * @return Closure A closure that will return true if called with an entity that has an attribute with name $name
+ * value $value.
+ */
+ public static function entityAttributeFactory($name, $value) {
+ return function(SimpleSAML_Metadata_SAMLParser $entityDesc) use ($name, $value) {
+ $metaData = sspmod_metarefresh_CommonFilters::getMetadata($entityDesc);
+ return isset($metaData['EntityAttributes'][$name]) && in_array($value,$metaData['EntityAttributes'][$name], true);
+ };
+ }
+
+ /**
+ * An internal helper function. Limitations in php 5.3 prevent referencing this helper function from anonymous methods
+ * unless it is public.
+ * @param SimpleSAML_Metadata_SAMLParser $entity
+ * @return array
+ */
+ public static function getMetadata(SimpleSAML_Metadata_SAMLParser $entity) {
+ $metaData = $entity->getMetadata20SP();
+ if (!isset($metaData)) {
+ $metaData = $entity->getMetadata20IdP();
+ }
+ if (!isset($metaData)) {
+ $metaData = $entity->getMetadata1xSP();
+ }
+ if (!isset($metaData)) {
+ $metaData = $entity->getMetadata1xIdP();
+ }
+ return $metaData;
+ }
+}
\ No newline at end of file
diff --git a/modules/metarefresh/lib/MetaLoader.php b/modules/metarefresh/lib/MetaLoader.php
index f34b58f..97f8bce 100644
--- a/modules/metarefresh/lib/MetaLoader.php
+++ b/modules/metarefresh/lib/MetaLoader.php
@@ -92,6 +92,29 @@ class sspmod_metarefresh_MetaLoader {
return;
}
+ $filterFunction = null;
+ if (isset($source['filterCallback'])) {
+ if (!is_callable($source['filterCallback'])) {
+ SimpleSAML_Logger::debug('Invalid filter callback ' . $source['filterCallback'] . ' - attempting to re-use cached metadata');
+ $this->addCachedMetadata($source);
+ return;
+ } else {
+ $filterFunction = $source['filterCallback'];
+ }
+ }
+
+ if(isset($source['filterFactory'])) {
+ if (isset($filterFunction)) {
+ SimpleSAML_Logger::warning("Both 'filterCallback' and 'filterFactory' defined. Ignoring 'filterFactory");
+ } elseif (is_callable($source['filterFactory'])) {
+ $filterFunction = call_user_func_array($source['filterFactory'], $source['filterFactoryArgs']);
+ } else {
+ SimpleSAML_Logger::debug('Invalid filter factory ' . $source['filterFactory'] . ' - attempting to re-use cached metadata');
+ $this->addCachedMetadata($source);
+ return;
+ }
+ }
+
foreach($entities as $entity) {
if(isset($source['blacklist'])) {
@@ -108,6 +131,13 @@ class sspmod_metarefresh_MetaLoader {
}
}
+ if(isset($filterFunction)) {
+ if (!call_user_func($filterFunction, $entity)) {
+ SimpleSAML_Logger::info('Skipping "' . $entity->getEntityID() . '" - filtered by custom filter.' . "\n");
+ continue;
+ }
+ }
+
if(array_key_exists('validateFingerprint', $source) && $source['validateFingerprint'] !== NULL) {
if(!$entity->validateFingerprint($source['validateFingerprint'])) {
SimpleSAML_Logger::info('Skipping "' . $entity->getEntityId() . '" - could not verify signature.' . "\n");
@@ -264,6 +294,13 @@ class sspmod_metarefresh_MetaLoader {
}
}
+ /**
+ * @return array returns the metadata array
+ */
+ public function getMetadata() {
+ return $this->metadata;
+ }
+
/**
* This function adds metadata from the specified file to the list of metadata.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment