diff --git a/src/Doctrine/AbstractMigration.php b/src/Doctrine/AbstractMigration.php index 6a9452b1..e85d49f8 100644 --- a/src/Doctrine/AbstractMigration.php +++ b/src/Doctrine/AbstractMigration.php @@ -18,6 +18,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface; /** * Base class for all Doctrine migrations. + * + * @codeCoverageIgnore */ abstract class AbstractMigration extends BaseAbstractMigration implements ContainerAwareInterface { diff --git a/tests/Export/Spreadsheet/EntityWithMetaFieldsExporterTest.php b/tests/Export/Spreadsheet/EntityWithMetaFieldsExporterTest.php index 9bb02c0c..70687d49 100644 --- a/tests/Export/Spreadsheet/EntityWithMetaFieldsExporterTest.php +++ b/tests/Export/Spreadsheet/EntityWithMetaFieldsExporterTest.php @@ -11,6 +11,7 @@ namespace App\Tests\Export\Spreadsheet; use App\Entity\Customer; use App\Entity\Project; +use App\Entity\ProjectMeta; use App\Event\ProjectMetaDisplayEvent; use App\Export\Spreadsheet\EntityWithMetaFieldsExporter; use App\Export\Spreadsheet\Extractor\AnnotationExtractor; @@ -29,9 +30,16 @@ class EntityWithMetaFieldsExporterTest extends TestCase { public function testExport() { + $dispatcher = $this->createMock(EventDispatcherInterface::class); + $dispatcher->expects(self::once())->method('dispatch')->willReturnCallback(function (ProjectMetaDisplayEvent $event) { + $event->addField((new ProjectMeta())->setName('foo meta')->setIsVisible(true)); + $event->addField((new ProjectMeta())->setName('hidden meta')->setIsVisible(false)); + $event->addField((new ProjectMeta())->setName('bar meta')->setIsVisible(true)); + }); + $spreadsheetExporter = new SpreadsheetExporter($this->createMock(TranslatorInterface::class)); $annotationExtractor = new AnnotationExtractor(new AnnotationReader()); - $metaFieldExtractor = new MetaFieldExtractor($this->createMock(EventDispatcherInterface::class)); + $metaFieldExtractor = new MetaFieldExtractor($dispatcher); $project = new Project(); $project->setName('test project'); @@ -42,6 +50,9 @@ class EntityWithMetaFieldsExporterTest extends TestCase $project->setTimeBudget(1234567890); $project->setColor('#ababab'); $project->setVisible(false); + $project->setMetaField((new ProjectMeta())->setName('foo meta')->setValue('some magic')->setIsVisible(true)); + $project->setMetaField((new ProjectMeta())->setName('hidden meta')->setValue('will not be seen')->setIsVisible(false)); + $project->setMetaField((new ProjectMeta())->setName('bar meta')->setValue('is happening')->setIsVisible(true)); $sut = new EntityWithMetaFieldsExporter($spreadsheetExporter, $annotationExtractor, $metaFieldExtractor); $spreadsheet = $sut->export(Project::class, [$project], new ProjectMetaDisplayEvent(new ProjectQuery(), ProjectMetaDisplayEvent::EXPORT)); @@ -57,5 +68,7 @@ class EntityWithMetaFieldsExporterTest extends TestCase self::assertEquals('#ababab', $worksheet->getCellByColumnAndRow(8, 2, false)->getValue()); self::assertFalse($worksheet->getCellByColumnAndRow(9, 2, false)->getValue()); self::assertEquals('Lorem Ipsum', $worksheet->getCellByColumnAndRow(10, 2, false)->getValue()); + self::assertEquals('some magic', $worksheet->getCellByColumnAndRow(11, 2, false)->getValue()); + self::assertEquals('is happening', $worksheet->getCellByColumnAndRow(12, 2, false)->getValue()); } } diff --git a/tests/Mocks/Saml/SamlAuthFactory.php b/tests/Mocks/Saml/SamlAuthFactory.php index 8223c71e..a1a7bbd5 100644 --- a/tests/Mocks/Saml/SamlAuthFactory.php +++ b/tests/Mocks/Saml/SamlAuthFactory.php @@ -16,7 +16,7 @@ use Symfony\Component\HttpFoundation\RequestStack; class SamlAuthFactory extends AbstractMockFactory { - public function create(?array $connection = null): SamlAuth + public function create(?array $connection = null, bool $fromTrustedProxy = false): SamlAuth { if (null === $connection) { $connection = [ @@ -76,8 +76,11 @@ class SamlAuthFactory extends AbstractMockFactory ]; } + $request = $this->getMockBuilder(Request::class)->getMock(); + $request->method('isFromTrustedProxy')->willReturn($fromTrustedProxy); + $requestStack = new RequestStack(); - $requestStack->push(new Request()); + $requestStack->push($request); return new SamlAuth($requestStack, $connection); } diff --git a/tests/Saml/Controller/SamlControllerTest.php b/tests/Saml/Controller/SamlControllerTest.php index 6f3b248d..84c33387 100644 --- a/tests/Saml/Controller/SamlControllerTest.php +++ b/tests/Saml/Controller/SamlControllerTest.php @@ -12,6 +12,11 @@ namespace App\Tests\Saml\Controller; use App\Saml\Controller\SamlController; use App\Tests\Mocks\Saml\SamlAuthFactory; use PHPUnit\Framework\TestCase; +use PHPUnit\Util\Xml; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Session\SessionInterface; +use Symfony\Component\Security\Core\Security; /** * @group integration @@ -42,4 +47,58 @@ class SamlControllerTest extends TestCase $sut = new SamlController($oauth); $sut->logoutAction(); } + + public function testMetadataAction() + { + $expected = << + + + + urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified + + + + Kimai + Kimai + https://www.kimai.org + + + Kimai Admin + kimai-tech@example.com + + + Kimai Support + kimai-support@example.com + + +EOD; + + $oauth = $this->getAuth(); + $sut = new SamlController($oauth); + $result = $sut->metadataAction(); + + self::assertInstanceOf(Response::class, $result); + self::assertEquals('xml', $result->headers->get('Content-Type')); + + $expected = Xml::load($expected); + $actual = Xml::load($result->getContent()); + + // the "validUntil" attribute in the outer node changes per request + self::assertEquals($expected->firstChild->firstChild, $actual->firstChild->firstChild); + } + + public function testLoginActionThrowsErrorOnSecurityErrorAttribute() + { + $this->expectException(\RuntimeException::class); + $this->expectExceptionMessage('My test error'); + + $request = new Request(); + $request->setSession($this->createMock(SessionInterface::class)); + $request->attributes->set(Security::AUTHENTICATION_ERROR, new \Exception('My test error')); + + $oauth = $this->getAuth(); + $sut = new SamlController($oauth); + $sut->loginAction($request); + } } diff --git a/tests/Saml/Provider/SamlProviderTest.php b/tests/Saml/Provider/SamlProviderTest.php index bf814e12..cfe1d114 100644 --- a/tests/Saml/Provider/SamlProviderTest.php +++ b/tests/Saml/Provider/SamlProviderTest.php @@ -19,6 +19,7 @@ use Hslavich\OneloginSamlBundle\Security\Authentication\Token\SamlToken; use PHPUnit\Framework\TestCase; use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; +use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\User\ChainUserProvider; /** @@ -26,7 +27,7 @@ use Symfony\Component\Security\Core\User\ChainUserProvider; */ class SamlProviderTest extends TestCase { - protected function getSamlProvider($mapping = null, $loadUser = false): SamlProvider + protected function getSamlProvider($mapping = null, $loadUser = false, ?SamlUserFactory $userFactory = null): SamlProvider { if (null === $mapping) { $mapping = [ @@ -41,12 +42,16 @@ class SamlProviderTest extends TestCase ]; } + if (null === $userFactory) { + $userFactory = new SamlUserFactory($mapping); + } + $repository = $this->getMockBuilder(UserRepository::class)->disableOriginalConstructor()->getMock(); if ($loadUser !== false) { $repository->expects($this->once())->method('loadUserByUsername')->willReturn($loadUser); } $userProvider = new ChainUserProvider([new DoctrineUserProvider($repository)]); - $provider = new SamlProvider($repository, $userProvider, new SamlTokenFactory(), new SamlUserFactory($mapping)); + $provider = new SamlProvider($repository, $userProvider, new SamlTokenFactory(), $userFactory); return $provider; } @@ -108,4 +113,22 @@ class SamlProviderTest extends TestCase self::assertEquals('Tralalala', $tokenUser->getTitle()); self::assertEquals('foo@example.com', $tokenUser->getEmail()); } + + public function testAuthenticateThrowsAuthenticationException() + { + $this->expectException(AuthenticationException::class); + $this->expectExceptionMessage('Failed creating or hydrating user "foo1@example.com": Missing user attribute: Email'); + + $user = new User(); + $user->setAuth(User::AUTH_SAML); + + $token = new SamlToken([]); + $token->setUser('foo1@example.com'); + $token->setAttributes([ + 'Chicken' => ['foo@example.com'], + ]); + + $sut = $this->getSamlProvider(null, $user); + $sut->authenticate($token); + } } diff --git a/tests/Saml/SamlAuthTest.php b/tests/Saml/SamlAuthTest.php new file mode 100644 index 00000000..c04b3a25 --- /dev/null +++ b/tests/Saml/SamlAuthTest.php @@ -0,0 +1,33 @@ +create(null, true); + + $current = Utils::getProxyVars(); + self::assertTrue($current); + + Utils::setProxyVars($previous); + } +} diff --git a/tests/Utils/MenuItemModelTest.php b/tests/Utils/MenuItemModelTest.php new file mode 100644 index 00000000..bd667c4b --- /dev/null +++ b/tests/Utils/MenuItemModelTest.php @@ -0,0 +1,37 @@ +isChildRoute('blub')); + self::assertFalse($sut->isChildRoute('bla')); + + $sut->addChildRoute('blub'); + + self::assertTrue($sut->isChildRoute('blub')); + self::assertFalse($sut->isChildRoute('bla')); + + $sut->setChildRoutes(['bla']); + + self::assertFalse($sut->isChildRoute('blub')); + self::assertTrue($sut->isChildRoute('bla')); + } +}