Skip to content
Merged
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
6 changes: 6 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Security

- **`allow_unauthenticated` refused in production.** The switch opens the layout admin to anonymous users; the
container now refuses to compile with it in the `prod` environment or in any non-debug kernel outside `test*`
environments (as ContactFormBundle).

## [1.8.1] - 2026-10-28

Security: the admin controllers are guarded by class, so a route name_prefix no longer bypasses the access check. See [UPGRADING](UPGRADING.md#to-181).
Expand Down
17 changes: 17 additions & 0 deletions src/DependencyInjection/NowoPageLayoutKitExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
use function array_key_exists;
use function is_array;
use function is_string;
use function str_starts_with;

/**
* Loads PageLayoutKit services and publishes configuration parameters.
Expand Down Expand Up @@ -117,6 +118,7 @@ public function getAlias(): string
private function registerAccessChecker(ContainerBuilder $container, array $security): void
{
if ($security['allow_unauthenticated']) {
$this->refuseAllowUnauthenticatedInProduction($container);
$id = 'nowo_page_layout_kit.access_checker.allow_all';
$container->setDefinition($id, new Definition(AllowAllPageLayoutKitAccessChecker::class));
$container->setAlias(PageLayoutKitAccessCheckerInterface::class, $id);
Expand Down Expand Up @@ -194,4 +196,19 @@ private function isSecurityBundleAvailable(ContainerBuilder $container): bool

return isset($bundles['SecurityBundle']);
}

/**
* `allow_unauthenticated` opens the layout admin to anonymous users: a dev / demo switch, refused in the prod
* environment and in any non-debug kernel outside the test environments (test*), as in ContactFormBundle.
*/
private function refuseAllowUnauthenticatedInProduction(ContainerBuilder $container): void
{
$environment = $container->hasParameter('kernel.environment') ? $container->getParameter('kernel.environment') : '';
$environment = is_string($environment) ? $environment : '';
$debug = $container->hasParameter('kernel.debug') ? (bool) $container->getParameter('kernel.debug') : true;

if ($environment === 'prod' || (!$debug && !str_starts_with($environment, 'test'))) {
throw new LogicException('nowo_page_layout_kit.security.allow_unauthenticated is a dev/demo switch: it opens the layout admin to anonymous users and is refused in the prod environment and in non-debug kernels (test* environments excepted).');
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use Nowo\PageLayoutKitBundle\Security\PageLayoutProtection;
use Nowo\PageLayoutKitBundle\Security\PageLayoutProtectionConfig;
use Nowo\PageLayoutKitBundle\Service\PageBlockMigrator;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\SecurityBundle\SecurityBundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;
Expand Down Expand Up @@ -98,6 +99,33 @@ public function testPrependPublishesTheDefaultFormKitProfileWhenMissing(): void
(new NowoPageLayoutKitExtension())->prepend($container);
}

/**
* @return iterable<string, array{string, bool, bool}>
*/
public static function allowUnauthenticatedKernels(): iterable
{
yield 'dev debug' => ['dev', true, true];
yield 'test without debug' => ['test', false, true];
yield 'prod' => ['prod', true, false];
yield 'staging without debug' => ['staging', false, false];
}

#[DataProvider('allowUnauthenticatedKernels')]
public function testAllowUnauthenticatedIsRefusedInProduction(string $environment, bool $debug, bool $allowed): void
{
$container = new ContainerBuilder();
$container->setParameter('kernel.environment', $environment);
$container->setParameter('kernel.debug', $debug);
if (!$allowed) {
$this->expectException(LogicException::class);
$this->expectExceptionMessage('dev/demo switch');
}

(new NowoPageLayoutKitExtension())->load([['security' => ['allow_unauthenticated' => true]]], $container);

self::assertTrue($container->hasDefinition('nowo_page_layout_kit.access_checker.allow_all'));
}

public function testLoadPublishesParametersAndRegistersAllowAllAccessChecker(): void
{
$container = new ContainerBuilder();
Expand Down
Loading