Refactor authentication system (#2602)
Make auth configuration available via UI, remove FOSUserBundle and SAML-Bundle dependency
This commit is contained in:
97
tests/EventSubscriber/EmailSubscriberTest.php
Normal file
97
tests/EventSubscriber/EmailSubscriberTest.php
Normal file
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Kimai time-tracking app.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace App\Tests\EventSubscriber;
|
||||
|
||||
use App\Entity\User;
|
||||
use App\Event\DashboardEvent;
|
||||
use App\Event\EmailEvent;
|
||||
use App\EventSubscriber\DashboardSubscriber;
|
||||
use App\EventSubscriber\EmailSubscriber;
|
||||
use App\Mail\KimaiMailer;
|
||||
use App\Repository\ActivityRepository;
|
||||
use App\Repository\CustomerRepository;
|
||||
use App\Repository\ProjectRepository;
|
||||
use App\Repository\UserRepository;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Mime\Email;
|
||||
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
|
||||
|
||||
/**
|
||||
* @covers \App\EventSubscriber\EmailSubscriber
|
||||
*/
|
||||
class EmailSubscriberTest extends TestCase
|
||||
{
|
||||
public function testGetSubscribedEvents()
|
||||
{
|
||||
$events = EmailSubscriber::getSubscribedEvents();
|
||||
$this->assertArrayHasKey(EmailEvent::class, $events);
|
||||
$methodName = $events[EmailEvent::class][0];
|
||||
$this->assertTrue(method_exists(EmailSubscriber::class, $methodName));
|
||||
}
|
||||
|
||||
public function testSendIsTriggered()
|
||||
{
|
||||
$mailer = $this->createMock(KimaiMailer::class);
|
||||
$mailer->expects($this->once())->method('send');
|
||||
|
||||
$sut = new EmailSubscriber($mailer);
|
||||
|
||||
$event = new EmailEvent(new Email());
|
||||
|
||||
$sut->onMailEvent($event);
|
||||
}
|
||||
|
||||
public function testWithAdminUser()
|
||||
{
|
||||
$sut = $this->getSubscriber(true, 13, 28, 37, 5);
|
||||
$event = new DashboardEvent(new User());
|
||||
|
||||
$this->assertEquals(0, \count($event->getSections()));
|
||||
$sut->onDashboardEvent($event);
|
||||
|
||||
$sections = $event->getSections();
|
||||
$widgets = $sections[0]->getWidgets();
|
||||
|
||||
$this->assertEquals(1, \count($sections));
|
||||
$this->assertEquals(4, \count($widgets));
|
||||
|
||||
$this->assertEquals('stats.userTotal', $widgets[0]->getTitle());
|
||||
$this->assertEquals(13, $widgets[0]->getData());
|
||||
|
||||
$this->assertEquals('stats.customerTotal', $widgets[1]->getTitle());
|
||||
$this->assertEquals(5, $widgets[1]->getData());
|
||||
|
||||
$this->assertEquals('stats.projectTotal', $widgets[2]->getTitle());
|
||||
$this->assertEquals(37, $widgets[2]->getData());
|
||||
|
||||
$this->assertEquals('stats.activityTotal', $widgets[3]->getTitle());
|
||||
$this->assertEquals(28, $widgets[3]->getData());
|
||||
}
|
||||
|
||||
protected function getSubscriber(bool $isAdmin, int $userCount, int $activityCount, int $projectCount, int $customerCount)
|
||||
{
|
||||
$authMock = $this->getMockBuilder(AuthorizationCheckerInterface::class)->getMock();
|
||||
$authMock->method('isGranted')->willReturn($isAdmin);
|
||||
|
||||
$userMock = $this->getMockBuilder(UserRepository::class)->disableOriginalConstructor()->getMock();
|
||||
$userMock->method('countUsersForQuery')->willReturn($userCount);
|
||||
|
||||
$projectMock = $this->getMockBuilder(ProjectRepository::class)->disableOriginalConstructor()->getMock();
|
||||
$projectMock->method('countProjectsForQuery')->willReturn($projectCount);
|
||||
|
||||
$activityMock = $this->getMockBuilder(ActivityRepository::class)->disableOriginalConstructor()->getMock();
|
||||
$activityMock->method('countActivitiesForQuery')->willReturn($activityCount);
|
||||
|
||||
$customerMock = $this->getMockBuilder(CustomerRepository::class)->disableOriginalConstructor()->getMock();
|
||||
$customerMock->method('countCustomersForQuery')->willReturn($customerCount);
|
||||
|
||||
return new DashboardSubscriber($authMock, $userMock, $activityMock, $projectMock, $customerMock);
|
||||
}
|
||||
}
|
||||
76
tests/EventSubscriber/LastLoginSubscriberTest.php
Normal file
76
tests/EventSubscriber/LastLoginSubscriberTest.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Kimai time-tracking app.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace App\Tests\EventSubscriber;
|
||||
|
||||
use App\Entity\User;
|
||||
use App\Event\UserInteractiveLoginEvent;
|
||||
use App\EventSubscriber\LastLoginSubscriber;
|
||||
use App\Repository\UserRepository;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
|
||||
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
|
||||
use Symfony\Component\Security\Http\SecurityEvents;
|
||||
|
||||
/**
|
||||
* @covers \App\EventSubscriber\LastLoginSubscriber
|
||||
*/
|
||||
class LastLoginSubscriberTest extends TestCase
|
||||
{
|
||||
public function testGetSubscribedEvents()
|
||||
{
|
||||
$events = LastLoginSubscriber::getSubscribedEvents();
|
||||
|
||||
$this->assertArrayHasKey(UserInteractiveLoginEvent::class, $events);
|
||||
$methodName = $events[UserInteractiveLoginEvent::class];
|
||||
$this->assertTrue(method_exists(LastLoginSubscriber::class, $methodName));
|
||||
|
||||
$this->assertArrayHasKey(SecurityEvents::INTERACTIVE_LOGIN, $events);
|
||||
$methodName = $events[SecurityEvents::INTERACTIVE_LOGIN];
|
||||
$this->assertTrue(method_exists(LastLoginSubscriber::class, $methodName));
|
||||
}
|
||||
|
||||
public function testOnImplicitLogin()
|
||||
{
|
||||
$repository = $this->createMock(UserRepository::class);
|
||||
$repository->expects($this->once())->method('saveUser');
|
||||
|
||||
$sut = new LastLoginSubscriber($repository);
|
||||
|
||||
$user = new User();
|
||||
self::assertNull($user->getLastLogin());
|
||||
|
||||
$event = new UserInteractiveLoginEvent($user);
|
||||
$sut->onImplicitLogin($event);
|
||||
self::assertNotNull($user->getLastLogin());
|
||||
}
|
||||
|
||||
public function testOnSecurityInteractiveLoginWithUser()
|
||||
{
|
||||
$repository = $this->createMock(UserRepository::class);
|
||||
$repository->expects($this->once())->method('saveUser');
|
||||
|
||||
$sut = new LastLoginSubscriber($repository);
|
||||
|
||||
$user = new User();
|
||||
self::assertNull($user->getLastLogin());
|
||||
|
||||
$event = new InteractiveLoginEvent(new Request(), new UsernamePasswordToken($user, [], 'sdf'));
|
||||
$sut->onSecurityInteractiveLogin($event);
|
||||
self::assertNotNull($user->getLastLogin());
|
||||
|
||||
$user = new User();
|
||||
self::assertNull($user->getLastLogin());
|
||||
|
||||
$event = new InteractiveLoginEvent(new Request(), new UsernamePasswordToken('foo', 'bar', 'sdf'));
|
||||
$sut->onSecurityInteractiveLogin($event);
|
||||
self::assertNull($user->getLastLogin());
|
||||
}
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Kimai time-tracking app.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace App\Tests\EventSubscriber;
|
||||
|
||||
use App\Entity\User;
|
||||
use App\EventSubscriber\RegistrationSubscriber;
|
||||
use FOS\UserBundle\Event\FormEvent;
|
||||
use FOS\UserBundle\FOSUserEvents;
|
||||
use FOS\UserBundle\Model\UserManagerInterface;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
|
||||
/**
|
||||
* @covers \App\EventSubscriber\RegistrationSubscriber
|
||||
*/
|
||||
class RegistrationSubscriberTest extends TestCase
|
||||
{
|
||||
public function testGetSubscribedEvents()
|
||||
{
|
||||
$events = RegistrationSubscriber::getSubscribedEvents();
|
||||
$this->assertArrayHasKey(FOSUserEvents::REGISTRATION_SUCCESS, $events);
|
||||
$methodName = $events[FOSUserEvents::REGISTRATION_SUCCESS][0];
|
||||
$this->assertTrue(method_exists(RegistrationSubscriber::class, $methodName));
|
||||
|
||||
$this->assertArrayHasKey(FOSUserEvents::RESETTING_RESET_SUCCESS, $events);
|
||||
$methodName = $events[FOSUserEvents::RESETTING_RESET_SUCCESS][0];
|
||||
$this->assertTrue(method_exists(RegistrationSubscriber::class, $methodName));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getTestData
|
||||
*/
|
||||
public function testRoleAssignmentForNewUser(array $existingUsers, $expectedRoles)
|
||||
{
|
||||
$user = new User();
|
||||
$user->setAlias('foo');
|
||||
$this->assertEquals([User::ROLE_USER], $user->getRoles());
|
||||
|
||||
$userManager = $this->getMockBuilder(UserManagerInterface::class)->getMock();
|
||||
$userManager->method('findUsers')->willReturn($existingUsers);
|
||||
|
||||
$form = $this->getMockBuilder(FormInterface::class)->getMock();
|
||||
$form->method('getData')->willReturn($user);
|
||||
|
||||
$request = $this->createMock(Request::class);
|
||||
$request->expects($this->any())->method('getLocale')->willReturn('ru');
|
||||
|
||||
$event = new FormEvent($form, $request);
|
||||
|
||||
$sut = new RegistrationSubscriber($userManager, $this->createMock(UrlGeneratorInterface::class));
|
||||
$sut->onRegistrationSuccess($event);
|
||||
|
||||
$this->assertEquals($expectedRoles, $user->getRoles());
|
||||
$this->assertEquals('ru', $user->getLanguage());
|
||||
}
|
||||
|
||||
public function getTestData()
|
||||
{
|
||||
return [
|
||||
// NewFirstUserGetsSuperAdminRole
|
||||
[[], [User::ROLE_SUPER_ADMIN, User::ROLE_USER]],
|
||||
// NewUserGetUserRole
|
||||
[[new User()], [User::ROLE_USER]],
|
||||
];
|
||||
}
|
||||
|
||||
public function testResetting()
|
||||
{
|
||||
$userManager = $this->createMock(UserManagerInterface::class);
|
||||
$form = $this->createMock(FormInterface::class);
|
||||
$request = $this->createMock(Request::class);
|
||||
$router = $this->createMock(UrlGeneratorInterface::class);
|
||||
|
||||
$router->expects($this->any())->method('generate')->willReturnArgument(0);
|
||||
$request->expects($this->any())->method('getLocale')->willReturn('ru');
|
||||
|
||||
$event = new FormEvent($form, $request);
|
||||
self::assertNull($event->getResponse());
|
||||
|
||||
$sut = new RegistrationSubscriber($userManager, $router);
|
||||
$sut->onResettingSuccess($event);
|
||||
|
||||
self::assertInstanceOf(RedirectResponse::class, $event->getResponse());
|
||||
|
||||
/** @var RedirectResponse $response */
|
||||
$response = $event->getResponse();
|
||||
self::assertEquals('my_profile', $response->getTargetUrl());
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Kimai time-tracking app.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace App\Tests\EventSubscriber;
|
||||
|
||||
use App\Entity\User;
|
||||
use App\EventSubscriber\ResetPasswordSubscriber;
|
||||
use App\Tests\Security\TestUserEntity;
|
||||
use FOS\UserBundle\Event\GetResponseNullableUserEvent;
|
||||
use FOS\UserBundle\FOSUserEvents;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
|
||||
/**
|
||||
* @covers \App\EventSubscriber\ResetPasswordSubscriber
|
||||
*/
|
||||
class ResetPasswordSubscriberTest extends TestCase
|
||||
{
|
||||
public function testGetSubscribedEvents()
|
||||
{
|
||||
$events = ResetPasswordSubscriber::getSubscribedEvents();
|
||||
self::assertCount(1, $events);
|
||||
$this->assertArrayHasKey(FOSUserEvents::RESETTING_SEND_EMAIL_INITIALIZE, $events);
|
||||
$methodName = $events[FOSUserEvents::RESETTING_SEND_EMAIL_INITIALIZE][0];
|
||||
$this->assertTrue(method_exists(ResetPasswordSubscriber::class, $methodName));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
*/
|
||||
public function testUnknownUserTypeIsIgnored()
|
||||
{
|
||||
$user = new TestUserEntity();
|
||||
$user->setUsername('foo@bar');
|
||||
|
||||
$request = $this->createMock(Request::class);
|
||||
$event = new GetResponseNullableUserEvent($user, $request);
|
||||
|
||||
$sut = new ResetPasswordSubscriber();
|
||||
$sut->onInitializeResetPassword($event);
|
||||
|
||||
self::assertNull($event->getResponse());
|
||||
}
|
||||
|
||||
public function testInternalAuthTypeIsIgnored()
|
||||
{
|
||||
$user = new User();
|
||||
$user->setUsername('foo@bar');
|
||||
|
||||
$request = $this->createMock(Request::class);
|
||||
$event = new GetResponseNullableUserEvent($user, $request);
|
||||
|
||||
$sut = new ResetPasswordSubscriber();
|
||||
$sut->onInitializeResetPassword($event);
|
||||
|
||||
self::assertNull($event->getResponse());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getAuthTypeData
|
||||
*/
|
||||
public function testNonInternalAuthTypeThrowsAccessDeniedException(string $authType)
|
||||
{
|
||||
$this->expectException(AccessDeniedHttpException::class);
|
||||
$this->expectExceptionMessage(sprintf('The user "foo@bar" tried to reset the password, but it is registered as "%s" auth-type.', $authType));
|
||||
|
||||
$user = new User();
|
||||
$user->setUsername('foo@bar');
|
||||
$user->setAuth($authType);
|
||||
|
||||
$request = $this->createMock(Request::class);
|
||||
$event = new GetResponseNullableUserEvent($user, $request);
|
||||
|
||||
$sut = new ResetPasswordSubscriber();
|
||||
$sut->onInitializeResetPassword($event);
|
||||
}
|
||||
|
||||
public function getAuthTypeData()
|
||||
{
|
||||
return [
|
||||
[User::AUTH_SAML],
|
||||
[User::AUTH_LDAP],
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user