Update CSRF Token IDs for Issue kevinpapst/kimai2#2947 (#2948)

* bump version
* removed not needed token, as it is already contained in the form
Co-authored-by: Kevin Papst <kpapst@gmx.net>
This commit is contained in:
tdozbun-reno
2021-11-18 11:32:00 -06:00
committed by GitHub
parent b28e9c120c
commit 56d02673ed
16 changed files with 35 additions and 113 deletions

View File

@@ -17,11 +17,11 @@ class Constants
/** /**
* The current release version * The current release version
*/ */
public const VERSION = '1.16.2'; public const VERSION = '1.16.3';
/** /**
* The current release: major * 10000 + minor * 100 + patch * The current release: major * 10000 + minor * 100 + patch
*/ */
public const VERSION_ID = 11602; public const VERSION_ID = 11603;
/** /**
* The current release status, either "stable" or "dev" * The current release status, either "stable" or "dev"
*/ */

View File

@@ -172,7 +172,7 @@ final class CustomerController extends AbstractController
return $this->redirectToRoute('customer_details', ['id' => $customerId]); return $this->redirectToRoute('customer_details', ['id' => $customerId]);
} }
$csrfTokenManager->refreshToken($token); $csrfTokenManager->refreshToken('customer.delete_comment');
try { try {
$this->repository->deleteComment($comment); $this->repository->deleteComment($comment);
@@ -219,7 +219,7 @@ final class CustomerController extends AbstractController
return $this->redirectToRoute('customer_details', ['id' => $customerId]); return $this->redirectToRoute('customer_details', ['id' => $customerId]);
} }
$csrfTokenManager->refreshToken($token); $csrfTokenManager->refreshToken('customer.pin_comment');
$comment->setPinned(!$comment->isPinned()); $comment->setPinned(!$comment->isPinned());
try { try {

View File

@@ -69,7 +69,7 @@ class DoctorController extends AbstractController
return $this->redirectToRoute('doctor'); return $this->redirectToRoute('doctor');
} }
$csrfTokenManager->refreshToken($token); $csrfTokenManager->refreshToken('doctor.flush_log');
$logfile = $this->getLogFilename(); $logfile = $this->getLogFilename();

View File

@@ -265,7 +265,7 @@ final class InvoiceController extends AbstractController
return $this->redirectToRoute('admin_invoice_list'); return $this->redirectToRoute('admin_invoice_list');
} }
$csrfTokenManager->refreshToken($token); $csrfTokenManager->refreshToken('invoice.delete');
try { try {
$this->service->deleteInvoice($invoice); $this->service->deleteInvoice($invoice);
@@ -462,7 +462,7 @@ final class InvoiceController extends AbstractController
return $this->redirectToRoute('admin_invoice_template'); return $this->redirectToRoute('admin_invoice_template');
} }
$csrfTokenManager->refreshToken($token); $csrfTokenManager->refreshToken('invoice.delete_template');
try { try {
$this->templateRepository->removeTemplate($template); $this->templateRepository->removeTemplate($template);

View File

@@ -194,7 +194,7 @@ final class ProjectController extends AbstractController
return $this->redirectToRoute('project_details', ['id' => $projectId]); return $this->redirectToRoute('project_details', ['id' => $projectId]);
} }
$csrfTokenManager->refreshToken($token); $csrfTokenManager->refreshToken('project.delete_comment');
try { try {
$this->repository->deleteComment($comment); $this->repository->deleteComment($comment);
@@ -241,7 +241,7 @@ final class ProjectController extends AbstractController
return $this->redirectToRoute('project_details', ['id' => $projectId]); return $this->redirectToRoute('project_details', ['id' => $projectId]);
} }
$csrfTokenManager->refreshToken($token); $csrfTokenManager->refreshToken('project.pin_comment');
$comment->setPinned(!$comment->isPinned()); $comment->setPinned(!$comment->isPinned());
try { try {
@@ -432,7 +432,7 @@ final class ProjectController extends AbstractController
return $this->redirectToRoute('project_details', ['id' => $project->getId()]); return $this->redirectToRoute('project_details', ['id' => $project->getId()]);
} }
$csrfTokenManager->refreshToken($token); $csrfTokenManager->refreshToken('project.duplicate');
$newProject = $projectDuplicationService->duplicate($project, $project->getName() . ' [COPY]'); $newProject = $projectDuplicationService->duplicate($project, $project->getName() . ' [COPY]');

View File

@@ -94,7 +94,7 @@ final class TeamController extends AbstractController
return $this->redirectToRoute('admin_team_edit', ['id' => $team->getId()]); return $this->redirectToRoute('admin_team_edit', ['id' => $team->getId()]);
} }
$csrfTokenManager->refreshToken($token); $csrfTokenManager->refreshToken('team.duplicate');
$newTeam = clone $team; $newTeam = clone $team;
$newTeam->setName($team->getName() . ' [COPY]'); $newTeam->setName($team->getName() . ' [COPY]');

View File

@@ -211,14 +211,14 @@ abstract class TimesheetAbstractController extends AbstractController
]); ]);
} }
protected function duplicate(Timesheet $timesheet, Request $request, string $renderTemplate, string $token): Response protected function duplicate(Timesheet $timesheet, Request $request, string $renderTemplate): Response
{ {
$copyTimesheet = clone $timesheet; $copyTimesheet = clone $timesheet;
$event = new TimesheetMetaDefinitionEvent($copyTimesheet); $event = new TimesheetMetaDefinitionEvent($copyTimesheet);
$this->dispatcher->dispatch($event); $this->dispatcher->dispatch($event);
$form = $this->getDuplicateForm($copyTimesheet, $timesheet, $token); $form = $this->getDuplicateForm($copyTimesheet, $timesheet);
$form->handleRequest($request); $form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) { if ($form->isSubmitted() && $form->isValid()) {
@@ -612,7 +612,7 @@ abstract class TimesheetAbstractController extends AbstractController
return $query; return $query;
} }
abstract protected function getDuplicateForm(Timesheet $entry, Timesheet $original, string $token): FormInterface; abstract protected function getDuplicateForm(Timesheet $entry, Timesheet $original): FormInterface;
abstract protected function getCreateForm(Timesheet $entry): FormInterface; abstract protected function getCreateForm(Timesheet $entry): FormInterface;
} }

View File

@@ -21,8 +21,6 @@ use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
/** /**
* @Route(path="/timesheet") * @Route(path="/timesheet")
@@ -62,20 +60,12 @@ class TimesheetController extends TimesheetAbstractController
} }
/** /**
* @Route(path="/{id}/duplicate/{token}", name="timesheet_duplicate", methods={"GET", "POST"}) * @Route(path="/{id}/duplicate", name="timesheet_duplicate", methods={"GET", "POST"})
* @Security("is_granted('duplicate', entry)") * @Security("is_granted('duplicate', entry)")
*/ */
public function duplicateAction(Timesheet $entry, Request $request, string $token, CsrfTokenManagerInterface $csrfTokenManager): Response public function duplicateAction(Timesheet $entry, Request $request): Response
{ {
if (!$csrfTokenManager->isTokenValid(new CsrfToken('timesheet.duplicate', $token))) { return $this->duplicate($entry, $request, 'timesheet/edit.html.twig');
$this->flashError('action.csrf.error');
return $this->redirectToRoute('timesheet');
}
$csrfTokenManager->refreshToken($token);
return $this->duplicate($entry, $request, 'timesheet/edit.html.twig', $token);
} }
/** /**
@@ -110,8 +100,8 @@ class TimesheetController extends TimesheetAbstractController
return $this->generateCreateForm($entry, TimesheetEditForm::class, $this->generateUrl('timesheet_create')); return $this->generateCreateForm($entry, TimesheetEditForm::class, $this->generateUrl('timesheet_create'));
} }
protected function getDuplicateForm(Timesheet $entry, Timesheet $original, string $token): FormInterface protected function getDuplicateForm(Timesheet $entry, Timesheet $original): FormInterface
{ {
return $this->generateCreateForm($entry, TimesheetEditForm::class, $this->generateUrl('timesheet_duplicate', ['id' => $original->getId(), 'token' => $token])); return $this->generateCreateForm($entry, TimesheetEditForm::class, $this->generateUrl('timesheet_duplicate', ['id' => $original->getId()]));
} }
} }

View File

@@ -28,8 +28,6 @@ use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
/** /**
* @Route(path="/team/timesheet") * @Route(path="/team/timesheet")
@@ -73,20 +71,12 @@ class TimesheetTeamController extends TimesheetAbstractController
} }
/** /**
* @Route(path="/{id}/duplicate/{token}", name="admin_timesheet_duplicate", methods={"GET", "POST"}) * @Route(path="/{id}/duplicate", name="admin_timesheet_duplicate", methods={"GET", "POST"})
* @Security("is_granted('duplicate', entry)") * @Security("is_granted('duplicate', entry)")
*/ */
public function duplicateAction(Timesheet $entry, Request $request, string $token, CsrfTokenManagerInterface $csrfTokenManager): Response public function duplicateAction(Timesheet $entry, Request $request): Response
{ {
if (!$csrfTokenManager->isTokenValid(new CsrfToken('admin_timesheet.duplicate', $token))) { return $this->duplicate($entry, $request, 'timesheet-team/edit.html.twig');
$this->flashError('action.csrf.error');
return $this->redirectToRoute('admin_timesheet');
}
$csrfTokenManager->refreshToken($token);
return $this->duplicate($entry, $request, 'timesheet-team/edit.html.twig', $token);
} }
/** /**
@@ -205,9 +195,9 @@ class TimesheetTeamController extends TimesheetAbstractController
return $this->generateCreateForm($entry, TimesheetAdminEditForm::class, $this->generateUrl('admin_timesheet_create')); return $this->generateCreateForm($entry, TimesheetAdminEditForm::class, $this->generateUrl('admin_timesheet_create'));
} }
protected function getDuplicateForm(Timesheet $entry, Timesheet $original, string $token): FormInterface protected function getDuplicateForm(Timesheet $entry, Timesheet $original): FormInterface
{ {
return $this->generateCreateForm($entry, TimesheetAdminEditForm::class, $this->generateUrl('admin_timesheet_duplicate', ['id' => $original->getId(), 'token' => $token])); return $this->generateCreateForm($entry, TimesheetAdminEditForm::class, $this->generateUrl('admin_timesheet_duplicate', ['id' => $original->getId()]));
} }
protected function getPermissionEditExport(): string protected function getPermissionEditExport(): string

View File

@@ -39,7 +39,7 @@ abstract class AbstractTimesheetSubscriber extends AbstractActionsSubscriber
if ($this->isGranted('duplicate', $timesheet)) { if ($this->isGranted('duplicate', $timesheet)) {
$class = $event->isView('edit') ? '' : 'modal-ajax-form'; $class = $event->isView('edit') ? '' : 'modal-ajax-form';
$event->addAction('copy', ['url' => $this->path($routeDuplicate, ['id' => $timesheet->getId(), 'token' => $payload['token']]), 'class' => $class]); $event->addAction('copy', ['url' => $this->path($routeDuplicate, ['id' => $timesheet->getId()]), 'class' => $class]);
} }
if ($event->countActions() > 0) { if ($event->countActions() > 0) {

View File

@@ -6,7 +6,7 @@
{% macro timesheet_team(timesheet, view) %} {% macro timesheet_team(timesheet, view) %}
{% import "macros/widgets.html.twig" as widgets %} {% import "macros/widgets.html.twig" as widgets %}
{% set event = actions(app.user, 'timesheet_team', view, {'timesheet': timesheet, 'token': csrf_token('admin_timesheet.duplicate')}) %} {% set event = actions(app.user, 'timesheet_team', view, {'timesheet': timesheet}) %}
{% if view == 'index' or view == 'custom' %} {% if view == 'index' or view == 'custom' %}
{{ widgets.table_actions(event.actions) }} {{ widgets.table_actions(event.actions) }}
{% else %} {% else %}

View File

@@ -6,7 +6,7 @@
{% macro timesheet(timesheet, view, options) %} {% macro timesheet(timesheet, view, options) %}
{% import "macros/widgets.html.twig" as widgets %} {% import "macros/widgets.html.twig" as widgets %}
{% set event = actions(app.user, 'timesheet', view, {'timesheet': timesheet, 'token': csrf_token('timesheet.duplicate')}) %} {% set event = actions(app.user, 'timesheet', view, {'timesheet': timesheet}) %}
{% if view == 'index' or view == 'custom' %} {% if view == 'index' or view == 'custom' %}
{{ widgets.table_actions(event.actions) }} {{ widgets.table_actions(event.actions) }}
{% else %} {% else %}

View File

@@ -241,8 +241,10 @@ class CustomerControllerTest extends ControllerBaseTest
$this->assertIsRedirect($client, $this->createUrl('/admin/customer/1/details')); $this->assertIsRedirect($client, $this->createUrl('/admin/customer/1/details'));
$client->followRedirect(); $client->followRedirect();
$node = $client->getCrawler()->filter('div.box#comments_box .box-body a.btn.active'); $node = $client->getCrawler()->filter('div.box#comments_box .box-body a.btn.active');
$token2 = self::$container->get('security.csrf.token_manager')->getToken('customer.pin_comment');
self::assertEquals(1, $node->count()); self::assertEquals(1, $node->count());
self::assertEquals($this->createUrl('/admin/customer/' . $id . '/comment_pin/' . $token), $node->attr('href')); self::assertEquals($this->createUrl('/admin/customer/' . $id . '/comment_pin/' . $token2), $node->attr('href'));
self::assertNotEquals($token, $token2);
} }
public function testCreateDefaultTeamAction() public function testCreateDefaultTeamAction()

View File

@@ -318,8 +318,10 @@ class ProjectControllerTest extends ControllerBaseTest
$this->assertIsRedirect($client, $this->createUrl('/admin/project/1/details')); $this->assertIsRedirect($client, $this->createUrl('/admin/project/1/details'));
$client->followRedirect(); $client->followRedirect();
$node = $client->getCrawler()->filter('div.box#comments_box .box-body a.btn.active'); $node = $client->getCrawler()->filter('div.box#comments_box .box-body a.btn.active');
$token2 = self::$container->get('security.csrf.token_manager')->getToken('project.pin_comment');
self::assertEquals(1, $node->count()); self::assertEquals(1, $node->count());
self::assertEquals($this->createUrl('/admin/project/' . $id . '/comment_pin/' . $token), $node->attr('href')); self::assertEquals($this->createUrl('/admin/project/' . $id . '/comment_pin/' . $token2), $node->attr('href'));
self::assertNotEquals($token, $token2);
} }
public function testCreateDefaultTeamAction() public function testCreateDefaultTeamAction()

View File

@@ -708,9 +708,7 @@ class TimesheetControllerTest extends ControllerBaseTest
$ids = $this->importFixture($fixture); $ids = $this->importFixture($fixture);
$newId = $ids[0]->getId(); $newId = $ids[0]->getId();
$token = self::$container->get('security.csrf.token_manager')->getToken('timesheet.duplicate'); $this->request($client, '/timesheet/' . $newId . '/duplicate');
$this->request($client, '/timesheet/' . $newId . '/duplicate/' . $token);
$this->assertTrue($client->getResponse()->isSuccessful()); $this->assertTrue($client->getResponse()->isSuccessful());
$form = $client->getCrawler()->filter('form[name=timesheet_edit_form]')->form(); $form = $client->getCrawler()->filter('form[name=timesheet_edit_form]')->form();
@@ -732,33 +730,4 @@ class TimesheetControllerTest extends ControllerBaseTest
$this->assertEquals(2016, $timesheet->getFixedRate()); $this->assertEquals(2016, $timesheet->getFixedRate());
$this->assertEquals(2016, $timesheet->getRate()); $this->assertEquals(2016, $timesheet->getRate());
} }
public function testDuplicateActionWithInvalidCsrf()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
$dateTime = new DateTimeFactory(new \DateTimeZone('Europe/London'));
$fixture = new TimesheetFixtures();
$fixture->setAmount(1);
$fixture->setAmountRunning(0);
$fixture->setUser($this->getUserByRole(User::ROLE_USER));
$fixture->setStartDate($dateTime->createDateTime());
$fixture->setCallback(function (Timesheet $timesheet) {
$timesheet->setDescription('Testing is fun!');
$begin = clone $timesheet->getBegin();
$begin->setTime(0, 0, 0);
$timesheet->setBegin($begin);
$end = clone $timesheet->getBegin();
$end->modify('+ 8 hours');
$timesheet->setEnd($end);
$timesheet->setFixedRate(2016);
$timesheet->setHourlyRate(127);
});
/** @var Timesheet[] $ids */
$ids = $this->importFixture($fixture);
$newId = $ids[0]->getId();
$this->assertInvalidCsrfToken($client, '/timesheet/' . $newId . '/duplicate/dfghdfghdfghdfghdfgh', $this->createUrl('/timesheet/'));
}
} }

View File

@@ -428,9 +428,7 @@ class TimesheetTeamControllerTest extends ControllerBaseTest
$ids = $this->importFixture($fixture); $ids = $this->importFixture($fixture);
$newId = $ids[0]->getId(); $newId = $ids[0]->getId();
$token = self::$container->get('security.csrf.token_manager')->getToken('admin_timesheet.duplicate'); $this->request($client, '/team/timesheet/' . $newId . '/duplicate');
$this->request($client, '/team/timesheet/' . $newId . '/duplicate/' . $token);
$this->assertTrue($client->getResponse()->isSuccessful()); $this->assertTrue($client->getResponse()->isSuccessful());
$form = $client->getCrawler()->filter('form[name=timesheet_admin_edit_form]')->form(); $form = $client->getCrawler()->filter('form[name=timesheet_admin_edit_form]')->form();
@@ -452,33 +450,4 @@ class TimesheetTeamControllerTest extends ControllerBaseTest
$this->assertEquals(2016, $timesheet->getFixedRate()); $this->assertEquals(2016, $timesheet->getFixedRate());
$this->assertEquals(2016, $timesheet->getRate()); $this->assertEquals(2016, $timesheet->getRate());
} }
public function testDuplicateActionWithInvalidCsrf()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
$dateTime = new DateTimeFactory(new \DateTimeZone('Europe/London'));
$fixture = new TimesheetFixtures();
$fixture->setAmount(1);
$fixture->setAmountRunning(0);
$fixture->setUser($this->getUserByRole(User::ROLE_USER));
$fixture->setStartDate($dateTime->createDateTime());
$fixture->setCallback(function (Timesheet $timesheet) {
$timesheet->setDescription('Testing is fun!');
$begin = clone $timesheet->getBegin();
$begin->setTime(0, 0, 0);
$timesheet->setBegin($begin);
$end = clone $timesheet->getBegin();
$end->modify('+ 8 hours');
$timesheet->setEnd($end);
$timesheet->setFixedRate(2016);
$timesheet->setHourlyRate(127);
});
/** @var Timesheet[] $ids */
$ids = $this->importFixture($fixture);
$newId = $ids[0]->getId();
$this->assertInvalidCsrfToken($client, '/team/timesheet/' . $newId . '/duplicate/dfghdfghdfghdfghdfgh', $this->createUrl('/team/timesheet/'));
}
} }