diff --git a/modules/core/lib/Controller/ErrorReport.php b/modules/core/lib/Controller/ErrorReport.php new file mode 100644 index 0000000000000000000000000000000000000000..1afb833c54ceaa24d4362761be640f4c66108323 --- /dev/null +++ b/modules/core/lib/Controller/ErrorReport.php @@ -0,0 +1,110 @@ +<?php + +declare(strict_types=1); + +namespace SimpleSAML\Module\core\Controller; + +use Exception; +use SimpleSAML\Configuration; +use SimpleSAML\Error; +use SimpleSAML\HTTP\RunnableResponse; +use SimpleSAML\Logger; +use SimpleSAML\Utils; +use SimpleSAML\XHTML\Template; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; + +use function dirname; +use function php_uname; +use function var_export; + +/** + * Controller class for the core module. + * + * This class serves the different views available in the module. + * + * @package SimpleSAML\Module\core + */ +class ErrorReport +{ + /** @var \SimpleSAML\Configuration */ + protected Configuration $config; + + + /** + * Controller constructor. + * + * It initializes the global configuration for the controllers implemented here. + * + * @param \SimpleSAML\Configuration $config The configuration to use by the controllers. + */ + public function __construct( + Configuration $config + ) { + $this->config = $config; + } + + + /** + * @param \Symfony\Component\HttpFoundation\Request $request + * @return \SimpleSAML\XHTML\Template|\SimpleSAML\HTTP\RunnableResponse + */ + public function main(Request $request): Response + { + // this page will redirect to itself after processing a POST request and sending the email + if ($request->server->get('REQUEST_METHOD') !== 'POST') { + // the message has been sent. Show error report page + + return new Template($this->config, 'core:errorreport.twig'); + } + + $reportId = $request->request->get('reportId'); + $email = $request->request->get('email'); + $text = $request->request->get('text'); + + if (!preg_match('/^[0-9a-f]{8}$/', $reportId)) { + throw new Error\Exception('Invalid reportID'); + } + + $data = null; + try { + $data = $this->session->getData('core:errorreport', $reportId); + } catch (Exception $e) { + Logger::error('Error loading error report data: ' . var_export($e->getMessage(), true)); + } + + if ($data === null) { + $data = [ + 'exceptionMsg' => 'not set', + 'exceptionTrace' => 'not set', + 'trackId' => 'not set', + 'url' => 'not set', + 'referer' => 'not set', + ]; + + if (isset($session)) { + $data['trackId'] = $session->getTrackID(); + } + } + + $data['reportId'] = $reportId; + $data['version'] = $this->config->getVersion(); + $data['hostname'] = php_uname('n'); + $data['directory'] = dirname(dirname(__FILE__)); + + if ($this->config->getOptionalBoolean('errorreporting', true)) { + $mail = new Utils\EMail('SimpleSAMLphp error report from ' . $email); + $mail->setData($data); + if (filter_var($email, FILTER_VALIDATE_EMAIL, FILTER_REQUIRE_SCALAR)) { + $mail->addReplyTo($email); + } + $mail->setText($text); + $mail->send(); + Logger::error('Report with id ' . $reportId . ' sent'); + } + + // redirect the user back to this page to clear the POST request + $httpUtils = new Utils\HTTP(); + return new RunnableResponse([$httpUtils, 'redirectTrustedURL'], [$httpUtils->getSelfURLNoQuery()]); + } +} diff --git a/modules/core/routing/routes/routes.yml b/modules/core/routing/routes/routes.yml index 7ed2a87b61145345a3a0a79e26f1996b322c9023..a41de34a1d17e4ef698d702824baaad930328708 100644 --- a/modules/core/routing/routes/routes.yml +++ b/modules/core/routing/routes/routes.yml @@ -49,3 +49,6 @@ core-logout-iframe-done: core-logout-iframe-post: path: /logout-iframe-post defaults: { _controller: 'SimpleSAML\Module\core\Controller\Logout::logoutIframePost' } +core-error-report: + path: /errorReport + defaults: { _controller: '\SimpleSAML\Module\core\Controller\ErrorReport::main' } diff --git a/templates/errorreport.twig b/modules/core/templates/errorreport.twig similarity index 100% rename from templates/errorreport.twig rename to modules/core/templates/errorreport.twig diff --git a/tests/modules/core/lib/Controller/ErrorReportTest.php b/tests/modules/core/lib/Controller/ErrorReportTest.php new file mode 100644 index 0000000000000000000000000000000000000000..9c893f0b82d3f8a7a3a41dcbe0b481d459fdd48b --- /dev/null +++ b/tests/modules/core/lib/Controller/ErrorReportTest.php @@ -0,0 +1,107 @@ +<?php + +declare(strict_types=1); + +namespace SimpleSAML\Test\Module\core\Controller; + +use PHPUnit\Framework\TestCase; +use SimpleSAML\Configuration; +use SimpleSAML\Error; +use SimpleSAML\HTTP\RunnableResponse; +use SimpleSAML\Module\core\Controller; +use SimpleSAML\XHTML\Template; +use Symfony\Component\HttpFoundation\Request; + +/** + * Set of tests for the controllers in the "core" module. + * + * @covers \SimpleSAML\Module\core\Controller\ErrorReport + * @package SimpleSAML\Test + */ +class ErrorReportTest extends TestCase +{ + /** @var \SimpleSAML\Configuration */ + protected Configuration $config; + + + /** + * Set up for each test. + */ + protected function setUp(): void + { + parent::setUp(); + + $this->config = Configuration::loadFromArray( + [ + 'errorreporting' => false, + 'module.enable' => ['core' => true], + ], + '[ARRAY]', + 'simplesaml' + ); + + Configuration::setPreLoadedConfig($this->config, 'config.php'); + } + + + /** + * Test that we are presented with an 'error was reported' page + */ + public function testErrorReportSent(): void + { + $request = Request::create( + '/errorReport', + 'GET', + ); + + $c = new Controller\ErrorReport($this->config); + + $response = $c->main($request); + + $this->assertInstanceOf(Template::class, $response); + $this->assertEquals('core:errorreport.twig', $response->getTemplateName()); + } + + + /** + * Test that we are presented with an 'error was reported' page + */ + public function testErrorReportIncorrectReportID(): void + { + $request = Request::create( + '/errorReport', + 'POST', + ['reportId' => 'abc123'], + ); + + $c = new Controller\ErrorReport($this->config); + + $this->expectException(Error\Exception::class); + $this->expectExceptionMessage('Invalid reportID'); + + $c->main($request); + } + + + /** + * Test that we are presented with an 'error was reported' page + */ + public function testErrorReport(): void + { + $request = Request::create( + '/errorReport', + 'POST', + [ + 'reportId' => 'abcd1234', + 'email' => 'phpunit@example.org', + 'text' => 'phpunit', + ], + ); + + $c = new Controller\ErrorReport($this->config); + + $response = $c->main($request); + + $this->assertInstanceOf(RunnableResponse::class, $response); + } +} diff --git a/www/errorreport.php b/www/errorreport.php deleted file mode 100644 index f2670417faf785545c193f98ae9a712e686bd5da..0000000000000000000000000000000000000000 --- a/www/errorreport.php +++ /dev/null @@ -1,64 +0,0 @@ -<?php - -require_once('_include.php'); - -$config = \SimpleSAML\Configuration::getInstance(); - -// this page will redirect to itself after processing a POST request and sending the email -if ($_SERVER['REQUEST_METHOD'] !== 'POST') { - // the message has been sent. Show error report page - - $t = new \SimpleSAML\XHTML\Template($config, 'errorreport.twig'); - $t->send(); - exit; -} - -$reportId = $_REQUEST['reportId']; -$email = $_REQUEST['email']; -$text = $_REQUEST['text']; - -if (!preg_match('/^[0-9a-f]{8}$/', $reportId)) { - throw new \SimpleSAML\Error\Exception('Invalid reportID'); -} - -$data = null; -try { - $session = \SimpleSAML\Session::getSessionFromRequest(); - $data = $session->getData('core:errorreport', $reportId); -} catch (\Exception $e) { - \SimpleSAML\Logger::error('Error loading error report data: ' . var_export($e->getMessage(), true)); -} - -if ($data === null) { - $data = [ - 'exceptionMsg' => 'not set', - 'exceptionTrace' => 'not set', - 'trackId' => 'not set', - 'url' => 'not set', - 'referer' => 'not set', - ]; - - if (isset($session)) { - $data['trackId'] = $session->getTrackID(); - } -} - -$data['reportId'] = $reportId; -$data['version'] = $config->getVersion(); -$data['hostname'] = php_uname('n'); -$data['directory'] = dirname(dirname(__FILE__)); - -if ($config->getOptionalBoolean('errorreporting', true)) { - $mail = new SimpleSAML\Utils\EMail('SimpleSAMLphp error report from ' . $email); - $mail->setData($data); - if (filter_var($email, FILTER_VALIDATE_EMAIL, FILTER_REQUIRE_SCALAR)) { - $mail->addReplyTo($email); - } - $mail->setText($text); - $mail->send(); - SimpleSAML\Logger::error('Report with id ' . $reportId . ' sent'); -} - -// redirect the user back to this page to clear the POST request -$httpUtils = new \SimpleSAML\Utils\HTTP(); -$httpUtils->redirectTrustedURL($httpUtils->getSelfURLNoQuery());