/** * This method applies the filter, removing any values * * @param array &$request the current request */ public function process(&$request) { $src = $request['Source']; if (!count($this->scopedAttributes)) { // paranoia, should never happen Logger::warning('No scoped attributes configured.'); return; } $validScopes = array(); if (array_key_exists('scope', $src) && is_array($src['scope']) && !empty($src['scope'])) { $validScopes = $src['scope']; } foreach ($this->scopedAttributes as $attribute) { if (!isset($request['Attributes'][$attribute])) { continue; } $values = $request['Attributes'][$attribute]; $newValues = array(); foreach ($values as $value) { $ep = \SimpleSAML\Utils\Config\Metadata::getDefaultEndpoint($request['Source']['SingleSignOnService']); $loc = $ep['Location']; $host = parse_url($loc, PHP_URL_HOST); if ($host === null) { $host = ''; } $value_a = explode('@', $value, 2); if (count($value_a) < 2) { $newValues[] = $value; continue; // there's no scope } $scope = $value_a[1]; if (in_array($scope, $validScopes, true)) { $newValues[] = $value; } elseif (strpos($host, $scope) === strlen($host) - strlen($scope)) { $newValues[] = $value; } else { Logger::warning("Removing value '{$value}' for attribute '{$attribute}'. Undeclared scope."); } } if (empty($newValues)) { Logger::warning("No suitable values for attribute '{$attribute}', removing it."); unset($request['Attributes'][$attribute]); // remove empty attributes } else { $request['Attributes'][$attribute] = $newValues; } } }
/** * Add contact information. * * Accepts a contact type, and a contact array that must be previously sanitized. * * WARNING: This function will change its signature and no longer parse a 'name' element. * * @param string $type The type of contact. Deprecated. * @param array $details The details about the contact. * * @todo Change the signature to remove $type. * @todo Remove the capability to pass a name and parse it inside the method. */ public function addContact($type, $details) { assert('is_string($type)'); assert('is_array($details)'); assert('in_array($type, array("technical", "support", "administrative", "billing", "other"), TRUE)'); // TODO: remove this check as soon as getContact() is called always before calling this function $details = \SimpleSAML\Utils\Config\Metadata::getContact($details); $e = new \SAML2\XML\md\ContactPerson(); $e->contactType = $type; if (isset($details['company'])) { $e->Company = $details['company']; } if (isset($details['givenName'])) { $e->GivenName = $details['givenName']; } if (isset($details['surName'])) { $e->SurName = $details['surName']; } if (isset($details['emailAddress'])) { $eas = $details['emailAddress']; if (!is_array($eas)) { $eas = array($eas); } foreach ($eas as $ea) { $e->EmailAddress[] = $ea; } } if (isset($details['telephoneNumber'])) { $tlfNrs = $details['telephoneNumber']; if (!is_array($tlfNrs)) { $tlfNrs = array($tlfNrs); } foreach ($tlfNrs as $tlfNr) { $e->TelephoneNumber[] = $tlfNr; } } $this->entityDescriptor->ContactPerson[] = $e; }
/** * Test \SimpleSAML\Utils\Config\Metadata::isHiddenFromDiscovery(). */ public function testIsHiddenFromDiscovery() { // test for success $metadata = array('EntityAttributes' => array(Metadata::$ENTITY_CATEGORY => array(Metadata::$HIDE_FROM_DISCOVERY))); $this->assertTrue(Metadata::isHiddenFromDiscovery($metadata)); // test for failures $this->assertFalse(Metadata::isHiddenFromDiscovery(array('foo'))); $this->assertFalse(Metadata::isHiddenFromDiscovery(array('EntityAttributes' => 'bar'))); $this->assertFalse(Metadata::isHiddenFromDiscovery(array('EntityAttributes' => array()))); $this->assertFalse(Metadata::isHiddenFromDiscovery(array('EntityAttributes' => array(Metadata::$ENTITY_CATEGORY => '')))); $this->assertFalse(Metadata::isHiddenFromDiscovery(array('EntityAttributes' => array(Metadata::$ENTITY_CATEGORY => array())))); }
if ($idpmeta->hasValue('UIInfo')) { $metaArray['UIInfo'] = $idpmeta->getArray('UIInfo'); } if ($idpmeta->hasValue('DiscoHints')) { $metaArray['DiscoHints'] = $idpmeta->getArray('DiscoHints'); } if ($idpmeta->hasValue('RegistrationInfo')) { $metaArray['RegistrationInfo'] = $idpmeta->getArray('RegistrationInfo'); } $metaflat = '$metadata[' . var_export($idpentityid, true) . '] = ' . var_export($metaArray, true) . ';'; $metaBuilder = new SimpleSAML_Metadata_SAMLBuilder($idpentityid); $metaBuilder->addSecurityTokenServiceType($metaArray); $metaBuilder->addOrganizationInfo($metaArray); $technicalContactEmail = $config->getString('technicalcontact_email', null); if ($technicalContactEmail && $technicalContactEmail !== '*****@*****.**') { $metaBuilder->addContact('technical', \SimpleSAML\Utils\Config\Metadata::getContact(array('emailAddress' => $technicalContactEmail, 'name' => $config->getString('technicalcontact_name', null), 'contactType' => 'technical'))); } $output_xhtml = array_key_exists('output', $_GET) && $_GET['output'] == 'xhtml'; $metaxml = $metaBuilder->getEntityDescriptorText($output_xhtml); if (!$output_xhtml) { $metaxml = str_replace("\n", '', $metaxml); } // sign the metadata if enabled $metaxml = SimpleSAML_Metadata_Signer::sign($metaxml, $idpmeta->toArray(), 'ADFS IdP'); if ($output_xhtml) { $defaultidp = $config->getString('default-adfs-idp', null); $t = new SimpleSAML_XHTML_Template($config, 'metadata.php', 'admin'); $t->data['clipboard.js'] = true; $t->data['available_certs'] = $availableCerts; $t->data['header'] = 'adfs-idp'; // TODO: Replace with headerString in 2.0
/** * Find the default endpoint of the given type. * * @param string $endpointType The endpoint type. * @param array $bindings Array with acceptable bindings. Can be null if any binding is allowed. * @param mixed $default The default value to return if no matching endpoint is found. If no default is provided, * an exception will be thrown. * * @return array|null The default endpoint, or null if no acceptable endpoints are used. * * @throws Exception If no supported endpoint is found. */ public function getDefaultEndpoint($endpointType, array $bindings = null, $default = self::REQUIRED_OPTION) { assert('is_string($endpointType)'); $endpoints = $this->getEndpoints($endpointType); $defaultEndpoint = \SimpleSAML\Utils\Config\Metadata::getDefaultEndpoint($endpoints, $bindings); if ($defaultEndpoint !== null) { return $defaultEndpoint; } if ($default === self::REQUIRED_OPTION) { $loc = $this->location . '[' . var_export($endpointType, true) . ']:'; throw new Exception($loc . 'Could not find a supported ' . $endpointType . ' endpoint.'); } return $default; }
} if ($idpmeta->hasValue('redirect.validate')) { $metaArray['redirect.sign'] = $idpmeta->getBoolean('redirect.validate'); } if ($idpmeta->hasValue('contacts')) { $contacts = $idpmeta->getArray('contacts'); foreach ($contacts as $contact) { $metaArray['contacts'][] = \SimpleSAML\Utils\Config\Metadata::getContact($contact); } } $technicalContactEmail = $config->getString('technicalcontact_email', false); if ($technicalContactEmail && $technicalContactEmail !== '*****@*****.**') { $techcontact['emailAddress'] = $technicalContactEmail; $techcontact['name'] = $config->getString('technicalcontact_name', null); $techcontact['contactType'] = 'technical'; $metaArray['contacts'][] = \SimpleSAML\Utils\Config\Metadata::getContact($techcontact); } $metaBuilder = new SimpleSAML_Metadata_SAMLBuilder($idpentityid); $metaBuilder->addMetadataIdP20($metaArray); $metaBuilder->addOrganizationInfo($metaArray); $metaxml = $metaBuilder->getEntityDescriptorText(); $metaflat = '$metadata[' . var_export($idpentityid, true) . '] = ' . var_export($metaArray, true) . ';'; // sign the metadata if enabled $metaxml = SimpleSAML_Metadata_Signer::sign($metaxml, $idpmeta->toArray(), 'SAML 2 IdP'); if (array_key_exists('output', $_GET) && $_GET['output'] == 'xhtml') { $defaultidp = $config->getString('default-saml20-idp', null); $t = new SimpleSAML_XHTML_Template($config, 'metadata.php', 'admin'); $t->data['clipboard.js'] = true; $t->data['available_certs'] = $availableCerts; $t->data['header'] = 'saml20-idp'; $t->data['metaurl'] = \SimpleSAML\Utils\HTTP::getSelfURLNoQuery();
/** * @deprecated This method will be removed in SSP 2.0. Please use SimpleSAML\Utils\Config\Metadata::getDefaultEndpoint() instead. */ public static function getDefaultEndpoint(array $endpoints, array $bindings = NULL) { return \SimpleSAML\Utils\Config\Metadata::getDefaultEndpoint($endpoints, $bindings); }
/** * Test contact configuration parsing and sanitizing. */ public function testGetContact() { // test missing type $contact = array('name' => 'John Doe'); try { $parsed = \SimpleSAML\Utils\Config\Metadata::getContact($contact); } catch (InvalidArgumentException $e) { $this->assertStringStartsWith('"contactType" is mandatory and must be one of ', $e->getMessage()); } // test invalid type $contact = array('contactType' => 'invalid'); try { $parsed = \SimpleSAML\Utils\Config\Metadata::getContact($contact); } catch (InvalidArgumentException $e) { $this->assertStringStartsWith('"contactType" is mandatory and must be one of ', $e->getMessage()); } // test all valid contact types foreach (\SimpleSAML\Utils\Config\Metadata::$VALID_CONTACT_TYPES as $type) { $contact = array('contactType' => $type); $parsed = \SimpleSAML\Utils\Config\Metadata::getContact($contact); $this->assertArrayHasKey('contactType', $parsed); $this->assertArrayNotHasKey('givenName', $parsed); $this->assertArrayNotHasKey('surName', $parsed); } // test basic name parsing $contact = array('contactType' => 'technical', 'name' => 'John Doe'); $parsed = \SimpleSAML\Utils\Config\Metadata::getContact($contact); $this->assertArrayNotHasKey('name', $parsed); $this->assertArrayHasKey('givenName', $parsed); $this->assertArrayHasKey('surName', $parsed); $this->assertEquals('John', $parsed['givenName']); $this->assertEquals('Doe', $parsed['surName']); // test comma-separated names $contact = array('contactType' => 'technical', 'name' => 'Doe, John'); $parsed = \SimpleSAML\Utils\Config\Metadata::getContact($contact); $this->assertArrayHasKey('givenName', $parsed); $this->assertArrayHasKey('surName', $parsed); $this->assertEquals('John', $parsed['givenName']); $this->assertEquals('Doe', $parsed['surName']); // test long names $contact = array('contactType' => 'technical', 'name' => 'John Fitzgerald Doe Smith'); $parsed = \SimpleSAML\Utils\Config\Metadata::getContact($contact); $this->assertArrayNotHasKey('name', $parsed); $this->assertArrayHasKey('givenName', $parsed); $this->assertArrayNotHasKey('surName', $parsed); $this->assertEquals('John Fitzgerald Doe Smith', $parsed['givenName']); // test comma-separated long names $contact = array('contactType' => 'technical', 'name' => 'Doe Smith, John Fitzgerald'); $parsed = \SimpleSAML\Utils\Config\Metadata::getContact($contact); $this->assertArrayNotHasKey('name', $parsed); $this->assertArrayHasKey('givenName', $parsed); $this->assertArrayHasKey('surName', $parsed); $this->assertEquals('John Fitzgerald', $parsed['givenName']); $this->assertEquals('Doe Smith', $parsed['surName']); // test givenName $contact = array('contactType' => 'technical'); $invalid_types = array(0, array(0), 0.1, true, false); foreach ($invalid_types as $type) { $contact['givenName'] = $type; try { \SimpleSAML\Utils\Config\Metadata::getContact($contact); } catch (InvalidArgumentException $e) { $this->assertEquals('"givenName" must be a string and cannot be empty.', $e->getMessage()); } } // test surName $contact = array('contactType' => 'technical'); $invalid_types = array(0, array(0), 0.1, true, false); foreach ($invalid_types as $type) { $contact['surName'] = $type; try { \SimpleSAML\Utils\Config\Metadata::getContact($contact); } catch (InvalidArgumentException $e) { $this->assertEquals('"surName" must be a string and cannot be empty.', $e->getMessage()); } } // test company $contact = array('contactType' => 'technical'); $invalid_types = array(0, array(0), 0.1, true, false); foreach ($invalid_types as $type) { $contact['company'] = $type; try { \SimpleSAML\Utils\Config\Metadata::getContact($contact); } catch (InvalidArgumentException $e) { $this->assertEquals('"company" must be a string and cannot be empty.', $e->getMessage()); } } // test emailAddress $contact = array('contactType' => 'technical'); $invalid_types = array(0, 0.1, true, false, array()); foreach ($invalid_types as $type) { $contact['emailAddress'] = $type; try { \SimpleSAML\Utils\Config\Metadata::getContact($contact); } catch (InvalidArgumentException $e) { $this->assertEquals('"emailAddress" must be a string or an array and cannot be empty.', $e->getMessage()); } } $invalid_types = array(array("string", true), array("string", 0)); foreach ($invalid_types as $type) { $contact['emailAddress'] = $type; try { \SimpleSAML\Utils\Config\Metadata::getContact($contact); } catch (InvalidArgumentException $e) { $this->assertEquals('Email addresses must be a string and cannot be empty.', $e->getMessage()); } } // test telephoneNumber $contact = array('contactType' => 'technical'); $invalid_types = array(0, 0.1, true, false, array()); foreach ($invalid_types as $type) { $contact['telephoneNumber'] = $type; try { \SimpleSAML\Utils\Config\Metadata::getContact($contact); } catch (InvalidArgumentException $e) { $this->assertEquals('"telephoneNumber" must be a string or an array and cannot be empty.', $e->getMessage()); } } $invalid_types = array(array("string", true), array("string", 0)); foreach ($invalid_types as $type) { $contact['telephoneNumber'] = $type; try { \SimpleSAML\Utils\Config\Metadata::getContact($contact); } catch (InvalidArgumentException $e) { $this->assertEquals('Telephone numbers must be a string and cannot be empty.', $e->getMessage()); } } // test completeness $contact = array(); foreach (\SimpleSAML\Utils\Config\Metadata::$VALID_CONTACT_OPTIONS as $option) { $contact[$option] = 'string'; } $contact['contactType'] = 'technical'; $contact['name'] = 'to_be_removed'; $parsed = \SimpleSAML\Utils\Config\Metadata::getContact($contact); foreach (array_keys($parsed) as $key) { $this->assertEquals($parsed[$key], $contact[$key]); } $this->assertArrayNotHasKey('name', $parsed); }
} if ($idpmeta->hasValue('redirect.validate')) { $metaArray['redirect.sign'] = $idpmeta->getBoolean('redirect.validate'); } if ($idpmeta->hasValue('contacts')) { $contacts = $idpmeta->getArray('contacts'); foreach ($contacts as $contact) { $metaArray['contacts'][] = Metadata::getContact($contact); } } $technicalContactEmail = $config->getString('technicalcontact_email', false); if ($technicalContactEmail && $technicalContactEmail !== '*****@*****.**') { $techcontact['emailAddress'] = $technicalContactEmail; $techcontact['name'] = $config->getString('technicalcontact_name', null); $techcontact['contactType'] = 'technical'; $metaArray['contacts'][] = Metadata::getContact($techcontact); } $metaBuilder = new SimpleSAML_Metadata_SAMLBuilder($idpentityid); $metaBuilder->addMetadataIdP20($metaArray); $metaBuilder->addOrganizationInfo($metaArray); $metaxml = $metaBuilder->getEntityDescriptorText(); $metaflat = '$metadata[' . var_export($idpentityid, true) . '] = ' . var_export($metaArray, true) . ';'; // sign the metadata if enabled $metaxml = SimpleSAML_Metadata_Signer::sign($metaxml, $idpmeta->toArray(), 'SAML 2 IdP'); if (array_key_exists('output', $_GET) && $_GET['output'] == 'xhtml') { $defaultidp = $config->getString('default-saml20-idp', null); $t = new SimpleSAML_XHTML_Template($config, 'metadata.php', 'admin'); $t->data['clipboard.js'] = true; $t->data['available_certs'] = $availableCerts; $t->data['header'] = 'saml20-idp'; // TODO: Replace with headerString in 2.0
if ($metadata['owner'] !== $userid) { throw new Exception('Metadata has an owner that is not equal to your userid, hence you are not granted access.'); } } if (array_key_exists('entityid', $_REQUEST)) { $metadata = $mdh->getMetadata($_REQUEST['entityid'], 'saml20-sp-remote'); requireOwnership($metadata, $userid); } elseif (array_key_exists('xmlmetadata', $_REQUEST)) { $xmldata = $_REQUEST['xmlmetadata']; \SimpleSAML\Utils\XML::checkSAMLMessage($xmldata, 'saml-meta'); $entities = SimpleSAML_Metadata_SAMLParser::parseDescriptorsString($xmldata); $entity = array_pop($entities); $metadata = $entity->getMetadata20SP(); /* Trim metadata endpoint arrays. */ $metadata['AssertionConsumerService'] = array(\SimpleSAML\Utils\Config\Metadata::getDefaultEndpoint($metadata['AssertionConsumerService'], array(SAML2_Const::BINDING_HTTP_POST))); $metadata['SingleLogoutService'] = array(\SimpleSAML\Utils\Config\Metadata::getDefaultEndpoint($metadata['SingleLogoutService'], array(SAML2_Const::BINDING_HTTP_REDIRECT))); } else { $metadata = array('owner' => $userid); } $editor = new sspmod_metaedit_MetaEditor(); if (isset($_POST['submit'])) { $editor->checkForm($_POST); $metadata = $editor->formToMeta($_POST, array(), array('owner' => $userid)); if (isset($_REQUEST['was-entityid']) && $_REQUEST['was-entityid'] !== $metadata['entityid']) { $premetadata = $mdh->getMetadata($_REQUEST['was-entityid'], 'saml20-sp-remote'); requireOwnership($premetadata, $userid); $mdh->deleteMetadata($_REQUEST['was-entityid'], 'saml20-sp-remote'); } $testmetadata = NULL; try { $testmetadata = $mdh->getMetadata($metadata['entityid'], 'saml20-sp-remote');