Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions config/packages/security.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ security:
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
providers:
admin_user_provider:
id: App\Security\AdminUserProvider
user_provider:
id: App\Security\UserProvider
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
Expand All @@ -17,7 +17,7 @@ security:
lazy: true
custom_authenticators:
- App\Security\LoginFormAuthenticator
provider: admin_user_provider
provider: user_provider
login_throttling:
max_attempts: 5
logout:
Expand All @@ -38,4 +38,4 @@ security:
- { path: ^/logout$, roles: PUBLIC_ACCESS }
- { path: ^/api/v1/health$, roles: PUBLIC_ACCESS }
- { path: ^/api, roles: IS_AUTHENTICATED }
- { path: ^/, roles: ROLE_ADMIN, allow_if: "'%env(default:default_admin_auth_bypass:ADMIN_AUTH_BYPASS)%' === 'true'" }
- { path: ^/, roles: [ROLE_ADMIN, ROLE_USER], allow_if: "'%env(default:default_admin_auth_bypass:ADMIN_AUTH_BYPASS)%' === 'true'" }
5 changes: 5 additions & 0 deletions config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ services:
$adminLogin: "%env(ADMIN_LOGIN)%"
$adminPassword: "%env(ADMIN_PASSWORD)%"

App\Security\UserProvider:
arguments:
$adminLogin: "%env(ADMIN_LOGIN)%"
$adminPassword: "%env(ADMIN_PASSWORD)%"

App\Logging\Monolog\PasswordFilterProcessor:
tags:
- { name: monolog.processor }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace App\Controller\Admin;
namespace App\Controller\User;

use App\Entity\AddressBook;
use App\Entity\Principal;
Expand All @@ -13,12 +13,14 @@
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
use Symfony\Contracts\Translation\TranslatorInterface;

#[Route('/addressbooks', name: 'addressbook_')]
class AddressBookController extends AbstractController
{
#[Route('/{userId}', name: 'index')]
#[IsGranted('access', 'userId')]
public function addressBooks(ManagerRegistry $doctrine, #[MapEntity(id: 'userId')] User $user, int $userId): Response
{
$principalUri = $user->getPrincipalUri();
Expand All @@ -40,6 +42,7 @@ public function addressBooks(ManagerRegistry $doctrine, #[MapEntity(id: 'userId'

#[Route('/{userId}/new', name: 'create')]
#[Route('/{userId}/edit/{id}', name: 'edit', requirements: ['id' => "\d+"])]
#[IsGranted('access', 'userId')]
public function addressbookCreate(ManagerRegistry $doctrine, Request $request, #[MapEntity(id: 'userId')] User $user, int $userId, ?int $id, TranslatorInterface $trans, BirthdayService $birthdayService): Response
{
$username = $user->getUsername();
Expand Down Expand Up @@ -102,6 +105,7 @@ public function addressbookCreate(ManagerRegistry $doctrine, Request $request, #
}

#[Route('/{userId}/delete/{id}', name: 'delete', requirements: ['id' => "\d+"], methods: ['POST'])]
#[IsGranted('access', 'userId')]
public function addressbookDelete(ManagerRegistry $doctrine, Request $request, #[MapEntity(id: 'userId')] User $user, int $userId, string $id, TranslatorInterface $trans, BirthdayService $birthdayService): Response
{
if (!$this->isCsrfTokenValid('admin_action', $request->getPayload()->getString('_token'))) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace App\Controller\Admin;
namespace App\Controller\User;

use App\Entity\Calendar;
use App\Entity\CalendarInstance;
Expand All @@ -18,12 +18,14 @@
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Http\Attribute\IsGranted;
use Symfony\Contracts\Translation\TranslatorInterface;

#[Route('/calendars', name: 'calendar_')]
class CalendarController extends AbstractController
{
#[Route('/{userId}', name: 'index')]
#[IsGranted('access', 'userId')]
public function calendars(ManagerRegistry $doctrine, UrlGeneratorInterface $router, #[MapEntity(id: 'userId')] User $user, int $userId): Response
{
$username = $user->getUsername();
Expand Down Expand Up @@ -74,6 +76,7 @@ public function calendars(ManagerRegistry $doctrine, UrlGeneratorInterface $rout

#[Route('/{userId}/new', name: 'create')]
#[Route('/{userId}/edit/{id}', name: 'edit', requirements: ['id' => "\d+"])]
#[IsGranted('access', 'userId')]
public function calendarEdit(ManagerRegistry $doctrine, Request $request, #[MapEntity(id: 'userId')] User $user, int $userId, ?int $id, TranslatorInterface $trans): Response
{
$principalUri = $user->getPrincipalUri();
Expand Down Expand Up @@ -163,6 +166,7 @@ public function calendarEdit(ManagerRegistry $doctrine, Request $request, #[MapE
}

#[Route('/{userId}/shares/{calendarid}', name: 'shares', requirements: ['calendarid' => "\d+"])]
#[IsGranted('access', 'userId')]
public function calendarShares(ManagerRegistry $doctrine, #[MapEntity(id: 'userId')] User $user, int $userId, string $calendarid, TranslatorInterface $trans): Response
{
$principalUri = $user->getPrincipalUri();
Expand All @@ -189,6 +193,7 @@ public function calendarShares(ManagerRegistry $doctrine, #[MapEntity(id: 'userI
}

#[Route('/{userId}/share/{instanceid}', name: 'share_add', requirements: ['instanceid' => "\d+"], methods: ['POST'])]
#[IsGranted('access', 'userId')]
public function calendarShareAdd(ManagerRegistry $doctrine, Request $request, #[MapEntity(id: 'userId')] User $user, int $userId, string $instanceid, TranslatorInterface $trans): Response
{
if (!$this->isCsrfTokenValid('admin_action', $request->getPayload()->getString('_token'))) {
Expand All @@ -203,11 +208,24 @@ public function calendarShareAdd(ManagerRegistry $doctrine, Request $request, #[
throw $this->createNotFoundException('Calendar not found');
}

if (!is_numeric($request->request->get('principalId'))) {
throw new BadRequestHttpException();
if ($this->isGranted('ROLE_ADMIN')) {
// in this case, this is the id of the principal to add
if (!is_numeric($request->request->get('principalId'))) {
throw new BadRequestHttpException();
}

$newShareeToAdd = $doctrine->getRepository(Principal::class)->findOneById($request->request->get('principalId'));
} else {
// in this case, this is the username of the user to add, we need to convert it to a principal
$userToAdd = $doctrine->getRepository(User::class)->findOneByUsername($request->request->get('principalId'));
if (!$userToAdd) {
$this->addFlash('warning', 'User does not exist');

return $this->redirectToRoute('calendar_index', ['userId' => $userId]);
}
$newShareeToAdd = $doctrine->getRepository(Principal::class)->findOneByUri($userToAdd->getPrincipalUri());
}

$newShareeToAdd = $doctrine->getRepository(Principal::class)->findOneById($request->request->get('principalId'));
if (!$newShareeToAdd) {
throw $this->createNotFoundException('Member not found');
}
Expand Down Expand Up @@ -246,6 +264,7 @@ public function calendarShareAdd(ManagerRegistry $doctrine, Request $request, #[
}

#[Route('/{userId}/delete/{id}', name: 'delete', requirements: ['id' => "\d+"], methods: ['POST'])]
#[IsGranted('access', 'userId')]
public function calendarDelete(ManagerRegistry $doctrine, Request $request, #[MapEntity(id: 'userId')] User $user, int $userId, string $id, TranslatorInterface $trans): Response
{
if (!$this->isCsrfTokenValid('admin_action', $request->getPayload()->getString('_token'))) {
Expand Down Expand Up @@ -301,6 +320,7 @@ public function calendarDelete(ManagerRegistry $doctrine, Request $request, #[Ma
}

#[Route('/{userId}/revoke/{id}', name: 'revoke', requirements: ['id' => "\d+"], methods: ['POST'])]
#[IsGranted('access', 'userId')]
public function calendarRevoke(ManagerRegistry $doctrine, Request $request, #[MapEntity(id: 'userId')] User $user, int $userId, string $id, TranslatorInterface $trans): Response
{
if (!$this->isCsrfTokenValid('admin_action', $request->getPayload()->getString('_token'))) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace App\Controller\Admin;
namespace App\Controller\User;

use App\Entity\AddressBook;
use App\Entity\CalendarInstance;
Expand All @@ -11,10 +11,12 @@
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;

class DashboardController extends AbstractController
{
#[Route('/dashboard', name: 'dashboard')]
#[IsGranted('ROLE_ADMIN')]
public function dashboard(ManagerRegistry $doctrine): Response
{
$usersCount = $doctrine->getRepository(User::class)->count([]);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace App\Controller\Admin;
namespace App\Controller\User;

use App\Entity\AddressBook;
use App\Entity\Calendar;
Expand All @@ -18,12 +18,14 @@
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
use Symfony\Contracts\Translation\TranslatorInterface;

#[Route('/users', name: 'user_')]
class UserController extends AbstractController
{
#[Route('/', name: 'index')]
#[IsGranted('ROLE_ADMIN')]
public function users(ManagerRegistry $doctrine): Response
{
$results = $doctrine->getRepository(Principal::class)->findAllMainPrincipalsWithUserIds();
Expand All @@ -33,8 +35,24 @@ public function users(ManagerRegistry $doctrine): Response
]);
}

#[Route('/{userId}', name: 'user', requirements: ['userId' => "\d+"])]
#[IsGranted('access', 'userId')]
public function user(ManagerRegistry $doctrine, #[MapEntity(id: 'userId')] User $user, int $userId): Response
{
$results = $doctrine->getRepository(Principal::class)->findOneMainPrincipalsWithUserId($userId);

if (!$results) {
throw BadRequestHttpException('User not found');
}

return $this->render('users/index.html.twig', [
'results' => $results,
]);
}

#[Route('/new', name: 'create')]
#[Route('/edit/{userId}', name: 'edit')]
#[IsGranted('access', 'userId')]
public function userCreate(ManagerRegistry $doctrine, Utils $utils, Request $request, ?int $userId, TranslatorInterface $trans): Response
{
if ($userId) {
Expand Down Expand Up @@ -115,7 +133,11 @@ public function userCreate(ManagerRegistry $doctrine, Utils $utils, Request $req

$this->addFlash('success', $trans->trans('user.saved'));

return $this->redirectToRoute('user_index');
if ($this->isGranted('ROLE_ADMIN')) {
return $this->redirectToRoute('user_index');
}

return $this->redirectToRoute('user_user', ['userId' => $userId]);
}

return $this->render('users/edit.html.twig', [
Expand All @@ -126,6 +148,7 @@ public function userCreate(ManagerRegistry $doctrine, Utils $utils, Request $req
}

#[Route('/delete/{userId}', name: 'delete', methods: ['POST'])]
#[IsGranted('access', 'userId')]
public function userDelete(ManagerRegistry $doctrine, Request $request, #[MapEntity(id: 'userId')] User $user, int $userId, TranslatorInterface $trans): Response
{
if (!$this->isCsrfTokenValid('admin_action', $request->getPayload()->getString('_token'))) {
Expand Down Expand Up @@ -195,10 +218,15 @@ public function userDelete(ManagerRegistry $doctrine, Request $request, #[MapEnt
$entityManager->flush();
$this->addFlash('success', $trans->trans('user.deleted'));

return $this->redirectToRoute('user_index');
if ($this->isGranted('ROLE_ADMIN')) {
return $this->redirectToRoute('user_index');
}

return $this->redirectToRoute('app_logout');
}

#[Route('/delegates/{userId}', name: 'delegates')]
#[IsGranted('access', 'userId')]
public function userDelegates(ManagerRegistry $doctrine, #[MapEntity(id: 'userId')] User $user, int $userId): Response
{
$principalUri = $user->getPrincipalUri();
Expand All @@ -222,6 +250,7 @@ public function userDelegates(ManagerRegistry $doctrine, #[MapEntity(id: 'userId
}

#[Route('/delegation/{userId}/{toggle}', name: 'delegation_toggle', requirements: ['toggle' => '(on|off)'], methods: ['POST'])]
#[IsGranted('access', 'userId')]
public function userToggleDelegation(ManagerRegistry $doctrine, Request $request, #[MapEntity(id: 'userId')] User $user, int $userId, string $toggle): Response
{
if (!$this->isCsrfTokenValid('admin_action', $request->getPayload()->getString('_token'))) {
Expand Down Expand Up @@ -265,19 +294,32 @@ public function userToggleDelegation(ManagerRegistry $doctrine, Request $request
}

#[Route('/delegates/{userId}/add', name: 'delegate_add', methods: ['POST'])]
#[IsGranted('access', 'userId')]
public function userDelegateAdd(ManagerRegistry $doctrine, Request $request, #[MapEntity(id: 'userId')] User $user, int $userId): Response
{
if (!$this->isCsrfTokenValid('admin_action', $request->getPayload()->getString('_token'))) {
throw $this->createAccessDeniedException('Invalid CSRF token.');
}

if (!is_numeric($request->request->get('principalId'))) {
throw new BadRequestHttpException();
}

$principalUri = $user->getPrincipalUri();

$newMemberToAdd = $doctrine->getRepository(Principal::class)->findOneById($request->request->get('principalId'));
if ($this->isGranted('ROLE_ADMIN')) {
// in this case, this is the id of the principal to add
if (!is_numeric($request->request->get('principalId'))) {
throw new BadRequestHttpException();
}

$newMemberToAdd = $doctrine->getRepository(Principal::class)->findOneById($request->request->get('principalId'));
} else {
// in this case, this is the username of the member to add, we need to convert it to a principal
$memberToAdd = $doctrine->getRepository(User::class)->findOneByUsername($request->request->get('principalId'));
if (!$memberToAdd) {
$this->addFlash('warning', 'User does not exist');

return $this->redirectToRoute('user_delegates', ['userId' => $userId]);
}
$newMemberToAdd = $doctrine->getRepository(Principal::class)->findOneByUri($memberToAdd->getPrincipalUri());
}

if (!$newMemberToAdd) {
throw $this->createNotFoundException('Member not found');
Expand Down Expand Up @@ -309,6 +351,7 @@ public function userDelegateAdd(ManagerRegistry $doctrine, Request $request, #[M
}

#[Route('/delegates/{userId}/remove/{principalProxyId}/{delegateId}', name: 'delegate_remove', requirements: ['principalProxyId' => "\d+", 'delegateId' => "\d+"], methods: ['POST'])]
#[IsGranted('access', 'userId')]
public function userDelegateRemove(ManagerRegistry $doctrine, Request $request, #[MapEntity(id: 'userId')] User $user, int $userId, int $principalProxyId, int $delegateId): Response
{
if (!$this->isCsrfTokenValid('admin_action', $request->getPayload()->getString('_token'))) {
Expand Down
22 changes: 22 additions & 0 deletions src/Repository/PrincipalRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,26 @@ public function findAllMainPrincipalsWithUserIds(): array
->getQuery()
->getResult();
}

/**
* @return array<array{Principal, userId: int}>
*/
public function findOneMainPrincipalsWithUserId(int $userId): array
{
return $this->createQueryBuilder('p')
->addSelect('u.id AS userId')
->leftJoin(
\App\Entity\User::class,
'u',
\Doctrine\ORM\Query\Expr\Join::WITH,
'CONCAT(:prefix, u.username) = p.uri'
)
->andWhere('p.isMain = :isMain')
->andWhere('u.id = :userid')
->setParameter('isMain', true)
->setParameter('userid', $userId)
->setParameter('prefix', Principal::PREFIX)
->getQuery()
->getResult();
}
}
Loading
Loading