diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index befbfa0..efc5198 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -21,7 +21,7 @@ jobs: matrix: php-version: ['8.3', '8.4', '8.5'] - uses: simplesamlphp/simplesamlphp-test-framework/.github/workflows/reusable_phplinter.yml@v1.11.1 + uses: simplesamlphp/simplesamlphp-test-framework/.github/workflows/reusable_phplinter.yml@v1.11.3 with: php-version: ${{ matrix.php-version }} @@ -30,7 +30,7 @@ jobs: strategy: fail-fast: false - uses: simplesamlphp/simplesamlphp-test-framework/.github/workflows/reusable_linter.yml@v1.11.1 + uses: simplesamlphp/simplesamlphp-test-framework/.github/workflows/reusable_linter.yml@v1.11.3 with: enable_eslinter: false enable_jsonlinter: true @@ -276,6 +276,6 @@ jobs: (needs.unit-tests-linux.result == 'success' && needs.coverage.result == 'skipped') steps: - - uses: geekyeggo/delete-artifact@v5 + - uses: geekyeggo/delete-artifact@v6 with: name: coverage-data diff --git a/bin/metarefresh.php b/bin/metarefresh.php index 4973c42..c90c212 100755 --- a/bin/metarefresh.php +++ b/bin/metarefresh.php @@ -12,7 +12,7 @@ $baseDir = dirname(__FILE__, 4); // Add library autoloader. -require_once($baseDir . '/lib/_autoload.php'); +require_once($baseDir . '/src/_autoload.php'); if (!\SimpleSAML\Module::isModuleEnabled('metarefresh')) { echo "You need to enable the metarefresh module before this script can be used.\n"; diff --git a/composer.json b/composer.json index 40bfe98..59d3e64 100644 --- a/composer.json +++ b/composer.json @@ -42,6 +42,7 @@ "simplesamlphp/simplesamlphp": "~2.5@dev", "simplesamlphp/xml-common": "~2.7", "symfony/http-foundation": "~7.4", + "symfony/http-client": "~7.4", "symfony/var-exporter": "~7.4" }, "require-dev": { diff --git a/src/MetaLoader.php b/src/MetaLoader.php index 77068fe..fcb46b0 100644 --- a/src/MetaLoader.php +++ b/src/MetaLoader.php @@ -10,6 +10,7 @@ use SimpleSAML\Metadata; use SimpleSAML\Utils; use SimpleSAML\XML\DOMDocumentFactory; +use Symfony\Component\HttpClient\Exception\TransportException; use Symfony\Component\VarExporter\VarExporter; /** @@ -108,27 +109,29 @@ public function loadSource(array $source): void $httpUtils = new Utils\HTTP(); $data = null; + // GET! + $client = $httpUtils->createHttpClient($context); + $response = $client->request('GET', $source['src'], $context); try { - /** @var array $response We know this because we set the third parameter to `true` */ - $response = $httpUtils->fetch($source['src'], $context, true); - list($data, $responseHeaders) = $response; - } catch (Exception $e) { - Logger::warning('metarefresh: ' . $e->getMessage()); + $statusCode = $response->getStatusCode(); + } catch (TransportException $e) { + Logger::info('No response from ' . $source['src'] . ' - attempting to re-use cached metadata.' + . ' The error was: ' . $e->getMessage()); + $this->addCachedMetadata($source); + return; } + $responseHeaders = $response->getHeaders(false); + $data = $response->getContent(false); + // We have response headers, so the request succeeded - if (!isset($responseHeaders)) { - // No response headers, this means the request failed in some way, so re-use old data - Logger::info('No response from ' . $source['src'] . ' - attempting to re-use cached metadata'); - $this->addCachedMetadata($source); - return; - } elseif (preg_match('@^HTTP/(2\.0|1\.[01])\s304\s@', $responseHeaders[0])) { + if ($statusCode === 304) { // 304 response Logger::debug('Received HTTP 304 (Not Modified) - attempting to re-use cached metadata'); $this->addCachedMetadata($source); return; - } elseif (!preg_match('@^HTTP/(2\.0|1\.[01])\s200\s@', $responseHeaders[0])) { + } elseif ($statusCode !== 200) { // Other error Logger::info('Error from ' . $source['src'] . ' - attempting to re-use cached metadata'); $this->addCachedMetadata($source); @@ -137,7 +140,7 @@ public function loadSource(array $source): void } else { // Local file. $data = file_get_contents($source['src']); - $responseHeaders = null; + $responseHeaders = []; } // Everything OK. Proceed. @@ -199,7 +202,7 @@ public function loadSource(array $source): void if (count($attributeAuthorities) && !empty($attributeAuthorities[0])) { $this->addMetadata( $source['src'], - $attributeAuthorities, + $attributeAuthorities[0], 'attributeauthority-remote', $template, ); @@ -384,23 +387,25 @@ private function createContext(array $source): array $name = $config->getOptionalString('technicalcontact_name', null); $mail = $config->getOptionalString('technicalcontact_email', null); - $rawheader = "User-Agent: SimpleSAMLphp metarefresh, run by $name <$mail>\r\n"; + $headers = [ + 'User-Agent' => "SimpleSAMLphp metarefresh, run by $name <$mail>", + ]; if (isset($source['conditionalGET']) && $source['conditionalGET']) { if (array_key_exists($source['src'], $this->state)) { $sourceState = $this->state[$source['src']]; if (isset($sourceState['last-modified'])) { - $rawheader .= 'If-Modified-Since: ' . $sourceState['last-modified'] . "\r\n"; + $headers['If-Modified-Since'] = $sourceState['last-modified']; } if (isset($sourceState['etag'])) { - $rawheader .= 'If-None-Match: ' . $sourceState['etag'] . "\r\n"; + $headers['If-None-Match'] = $sourceState['etag']; } } } - return ['http' => ['header' => $rawheader]]; + return ['headers' => $headers]; } @@ -427,13 +432,13 @@ private function addCachedMetadata(array $source): void * Store caching state data for a source * * @param array $source - * @param array|null $responseHeaders + * @param array $responseHeaders */ - private function saveState(array $source, ?array $responseHeaders): void + private function saveState(array $source, array $responseHeaders): void { if (isset($source['conditionalGET']) && $source['conditionalGET']) { // Headers section - if ($responseHeaders !== null) { + if ($responseHeaders !== []) { $candidates = ['last-modified', 'etag']; foreach ($candidates as $candidate) { diff --git a/tests/src/Controller/MetaRefreshTest.php b/tests/src/Controller/MetaRefreshTest.php index 3e45b96..bd9418f 100644 --- a/tests/src/Controller/MetaRefreshTest.php +++ b/tests/src/Controller/MetaRefreshTest.php @@ -52,7 +52,7 @@ protected function setUp(): void 'cron' => ['hourly'], 'sources' => [ [ - 'src' => 'https://example.org/simplesaml/module.php/aggregator/?id=kalmarcentral&set=saml2&exclude=norway', + 'src' => 'https://nexus.microsoftonline-p.com/federationmetadata/saml20/federationmetadata.xml', ], ], 'outputFormat' => 'flatfile', @@ -104,6 +104,5 @@ public function testMetaRefresh(): void $contents = $response->getContents(); $this->assertStringContainsString('[metarefresh]: Executing set [example]', $contents); $this->assertStringContainsString('In set [example] loading source', $contents); - $this->assertStringContainsString('attempting to re-use cached metadata', $contents); } }