CVE-2024-27915 (PHP, published 2024-03-06T20:15Z)
Description: value: Sulu is a PHP content management system. Starting in verson 2.2.0 and prior to version 2.4.17 and 2.5.13, access to pages is granted regardless of role permissions for webspaces which have a security system configured and permission check enabled. Webspaces without do not have this issue. The problem is patched in versions 2.4.17 and 2.5.13. Some workarounds are available. One may apply the patch to `vendor/symfony/security-http/HttpUtils.php` manually or avoid installing `symfony/security-http` versions greater equal than `v5.4.30` or `v6.3.6`.
Severity: nan (CVSS v3 base score: )
Weakness: NVD-CWE-noinfo \u2014 Insufficient Information
There is insufficient information about the issue to classify it; details are unkown or unspecified.
Repository: https://github.com/sulu/sulu
Files changed:
phpstan-baseline.neon
src/Sulu/Bundle/CoreBundle/Resources/config/request_analyzer.xml
src/Sulu/Bundle/SecurityBundle/EventListener/SystemListener.php
src/Sulu/Bundle/SecurityBundle/Resources/config/services.xml
src/Sulu/Bundle/SecurityBundle/Tests/Unit/EventListener/SystemListenerTest.php
src/Sulu/Bundle/WebsiteBundle/EventListener/RouterListener.php
src/Sulu/Bundle/WebsiteBundle/EventListener/SecurityListener.php
src/Sulu/Bundle/WebsiteBundle/Resources/config/services.xml
src/Sulu/Bundle/WebsiteBundle/Resources/config/website.xml
src/Sulu/Bundle/WebsiteBundle/Routing/ContentRouteProvider.php
src/Sulu/Bundle/WebsiteBundle/Tests/Application/Kernel.php
src/Sulu/Bundle/WebsiteBundle/Tests/Application/config/config_with_security.yml
src/Sulu/Bundle/WebsiteBundle/Tests/Application/config/routing_website.yml
src/Sulu/Bundle/WebsiteBundle/Tests/Application/config/webspaces/sulu_lo.xml
src/Sulu/Bundle/WebsiteBundle/Tests/Functional/EventListener/SecurityListenerTest.php
src/Sulu/Bundle/WebsiteBundle/Tests/Unit/Routing/ContentRouteProviderTest.php
src/Sulu/Component/Webspace/Analyzer/Attributes/SystemRequestProcessor.php
Commit message: Merge pull request from GHSA-jr83-m233-gg6p

* Fix setting of Webspace Security System before Symfony RouteListener

* Fix Redirect for Security System checker error

* Add test case to avoid regression

* Add test for none secured pages

* Fix some PHP 7.2 issues

* Remmove website based system listener test

* Activate security only for specific test

* Remove old ContentRouteProviderTests

* Fix phpcs

* Skip security listener test for older symfony security system

* Fix code style

* Fix phpstan issues

* Throw deprecation when requestAnalyzer is still given

* Fix code style

* Mark new service as internal and final

Vulnerable code:
			message: "#^If condition is always true\\.$#"
			message: "#^Method Sulu\\\\Bundle\\\\SecurityBundle\\\\EventListener\\\\SystemListener\\:\\:onKernelRequest\\(\\) has no return type specified\\.$#"
		-
			message: "#^Method Sulu\\\\Bundle\\\\SecurityBundle\\\\EventListener\\\\SystemListenerTest\\:\\:provideSetWebsiteSystem\\(\\) has no return type specified\\.$#"
			count: 1
			path: src/Sulu/Bundle/SecurityBundle/Tests/Unit/EventListener/SystemListenerTest.php

     * @var RequestAnalyzerInterface
        RequestAnalyzerInterface $requestAnalyzer,

        $webspace = $this->requestAnalyzer->getWebspace();
        if ($webspace) {
            $security = $webspace->getSecurity();
            if ($security) {
                $this->systemStore->setSystem($security->getSystem());

                return;
            }
        }
            <argument type="service" id="sulu_core.webspace.request_analyzer"/>
use Sulu\Component\Webspace\Security;
use Sulu\Component\Webspace\Webspace;
    public function provideSetWebsiteSystem()
    {
        return [
            ['sulu-test'],
            ['sulu-blog'],
        ];
    }

    /**
     * @dataProvider provideSetWebsiteSystem
     */
    public function testSetWebsiteSystem(string $system): void
    {
        $systemListener = $this->createSystemListener('website');
        $requestEvent = $this->prophesize(RequestEvent::class);

        $webspace = new Webspace();
        $security = new Security();
        $security->setSystem($system);
        $webspace->setSecurity($security);
        $this->requestAnalyzer->getWebspace()->willReturn($webspace);

        $systemListener->onKernelRequest($requestEvent->reveal());

        $this->systemStore->setSystem($system)->shouldBeCalled();
    }

            <argument type="service" id="sulu_security.security_checker" on-invalid="null"/>
use Sulu\Component\Security\Authorization\PermissionTypes;
use Sulu\Component\Security\Authorization\SecurityCondition;
            if ($this->securityChecker && $portal->getWebspace()->hasWebsiteSecurity()) {
                $this->securityChecker->checkPermission(
                    new SecurityCondition(
                        'sulu.webspaces.' . $document->getWebspaceName(),
                        $document->getLocale(),
                        \get_class($document),
                        $document->getUuid()
                    ),
                    PermissionTypes::VIEW
                );
            }

        parent::__construct($environment, $debug, $suluContext);

use Sulu\Component\Security\Authorization\PermissionTypes;
use Sulu\Component\Security\Authorization\SecurityCondition;
use Sulu\Component\Webspace\Security;
    public function testSecurityChecker(): void
    {
        $attributes = $this->prophesize(RequestAttributes::class);

        $attributes->getAttribute('localization', null)->willReturn(new Localization('de'));

        $portal = new Portal();
        $portal->setKey('portal');
        $webspace = new Webspace();
        $webspace->setKey('webspace');
        $webspace->setTheme('theme');
        $security = new Security();
        $security->setSystem('website');
        $security->setPermissionCheck(true);
        $webspace->setSecurity($security);
        $portal->setWebspace($webspace);
        $attributes->getAttribute('portal', null)->willReturn($portal);

        $attributes->getAttribute('matchType', null)->willReturn(RequestAnalyzer::MATCH_TYPE_FULL);
        $attributes->getAttribute('resourceLocator', null)->willReturn(null);
        $attributes->getAttribute('resourceLocatorPrefix', null)->willReturn('/de');

        $this->resourceLocatorStrategy->loadByResourceLocator('', 'webspace', 'de')->willReturn('some-uuid');

        $document = $this->prophesize(TitleBehavior::class)
            ->willImplement(ExtensionBehavior::class)
            ->willImplement(RedirectTypeBehavior::class)
            ->willImplement(StructureBehavior::class)
            ->willImplement(WebspaceBehavior::class)
            ->willImplement(UuidBehavior::class);
        $document->getUuid()->willReturn('some-uuid');
        $document->getTitle()->willReturn('some-title');
        $document->getWebspaceName()->willReturn('webspace');
        $document->getLocale()->willReturn('de');
        $document->getRedirectType()->willReturn(RedirectType::NONE);
        $document->getStructureType()->willReturn('default');
        $document->getUuid()->willReturn('some-uuid');
        $document->getExtensionsData()->willReturn(['excerpt' => ['segments' => null]]);
        $this->documentManager->find('some-uuid', 'de', ['load_ghost_content' => false])->willReturn($document->reveal());

        $metadata = new Metadata();
        $metadata->setAlias('page');
        $structureMetadata = new StructureMetadata();
        $this->documentInspector->getMetadata($document->reveal())->willReturn($metadata);
        $this->documentInspector->getStructureMetadata($document->reveal())->willReturn($structureMetadata);

        $pageBridge = $this->prophesize(PageBridge::class);
        $pageBridge->getController()->willReturn('::Controller');
        $this->structureManager->wrapStructure('page', $structureMetadata)->willReturn($pageBridge->reveal());

        $request = new Request(
            [],
            [],
            ['_sulu' => $attributes->reveal()],
            [],
            [],
            ['REQUEST_URI' => \rawurlencode('/de')]
        );

        $pageBridge->setDocument($document->reveal())->shouldBeCalled();

        $securityChecker = $this->prophesize(SecurityCheckerInterface::class);
        $securityChecker->checkPermission(Argument::that(function(SecurityCondition $securityCondition) use ($document) {
            $this->assertSame('some-uuid', $securityCondition->getObjectId());
            $this->assertSame(\get_class($document->reveal()), $securityCondition->getObjectType());
            $this->assertSame('de', $securityCondition->getLocale());
            $this->assertSame('sulu.webspaces.webspace', $securityCondition->getSecurityContext());

            return true;
        }), PermissionTypes::VIEW)->shouldBeCalled();

        $contentRouteProvider = $this->createContentRouteProvider($securityChecker->reveal());
        $routes = $contentRouteProvider->getRouteCollectionForRequest($request);

        $defaults = $routes->getIterator()->current()->getDefaults();

        $this->assertCount(1, $routes);
        $this->assertEquals($pageBridge->reveal(), $defaults['structure']);
        $this->assertEquals(false, $defaults['partial']);
    }

    public function testSecurityCheckerWithoutPermissionCheck(): void
    {
        $attributes = $this->prophesize(RequestAttributes::class);

        $attributes->getAttribute('localization', null)->willReturn(new Localization('de'));

        $portal = new Portal();
        $portal->setKey('portal');
        $webspace = new Webspace();
        $webspace->setKey('webspace');
        $webspace->setTheme('theme');
        $security = new Security();
        $security->setSystem('website');
        $security->setPermissionCheck(false);
        $webspace->setSecurity($security);
        $portal->setWebspace($webspace);
        $attributes->getAttribute('portal', null)->willReturn($portal);

        $attributes->getAttribute('matchType', null)->willReturn(RequestAnalyzer::MATCH_TYPE_FULL);
        $attributes->getAttribute('resourceLocator', null)->willReturn(null);
        $attributes->getAttribute('resourceLocatorPrefix', null)->willReturn('/de');

        $this->resourceLocatorStrategy->loadByResourceLocator('', 'webspace', 'de')->willReturn('some-uuid');

        $document = $this->prophesize(TitleBehavior::class)
            ->willImplement(ExtensionBehavior::class)
            ->willImplement(RedirectTypeBehavior::class)
            ->willImplement(StructureBehavior::class)
            ->willImplement(WebspaceBehavior::class)
            ->willImplement(UuidBehavior::class);
        $document->getUuid()->willReturn('some-uuid');
        $document->getTitle()->willReturn('some-title');
        $document->getWebspaceName()->willReturn('webspace');
        $document->getLocale()->willReturn('de');
        $document->getRedirectType()->willReturn(RedirectType::NONE);
        $document->getStructureType()->willReturn('default');
        $document->getUuid()->willReturn('some-uuid');
        $document->getExtensionsData()->willReturn(['excerpt' => ['segments' => null]]);
        $this->documentManager->find('some-uuid', 'de', ['load_ghost_content' => false])->willReturn($document->reveal());

        $metadata = new Metadata();
        $metadata->setAlias('page');
        $structureMetadata = new StructureMetadata();
        $this->documentInspector->getMetadata($document->reveal())->willReturn($metadata);
        $this->documentInspector->getStructureMetadata($document->reveal())->willReturn($structureMetadata);

        $pageBridge = $this->prophesize(PageBridge::class);
        $pageBridge->getController()->willReturn('::Controller');
        $this->structureManager->wrapStructure('page', $structureMetadata)->willReturn($pageBridge->reveal());

        $request = new Request(
            [],
            [],
            ['_sulu' => $attributes->reveal()],
            [],
            [],
            ['REQUEST_URI' => \rawurlencode('/de')]
        );

        $pageBridge->setDocument($document->reveal())->shouldBeCalled();

        $securityChecker = $this->prophesize(SecurityCheckerInterface::class);
        $securityChecker->checkPermission(Argument::cetera())->shouldNotBeCalled();

        $contentRouteProvider = $this->createContentRouteProvider($securityChecker->reveal());
        $routes = $contentRouteProvider->getRouteCollectionForRequest($request);

        $defaults = $routes->getIterator()->current()->getDefaults();

        $this->assertCount(1, $routes);
        $this->assertEquals($pageBridge->reveal(), $defaults['structure']);
        $this->assertEquals(false, $defaults['partial']);
    }


Fixed code:
			message: "#^Method Sulu\\\\Bundle\\\\SecurityBundle\\\\EventListener\\\\SystemListener\\:\\:onKernelRequest\\(\\) has no return type specified\\.$#"
			message: "#^Property Sulu\\\\Bundle\\\\SecurityBundle\\\\EventListener\\\\SystemListener\\:\\:\\$requestAnalyzer is never read, only written\\.$#"
		-
			message: "#^Property Sulu\\\\Bundle\\\\WebsiteBundle\\\\Routing\\\\ContentRouteProvider\\:\\:\\$securityChecker is never read, only written\\.$#"
			count: 1
			path: src/Sulu/Bundle/WebsiteBundle/Routing/ContentRouteProvider.php

        <service id="sulu_core.request_processor.system"
                 class="Sulu\Component\Webspace\Analyzer\Attributes\SystemRequestProcessor">
            <argument type="service" id="sulu_security.system_store" />
            <argument>%sulu.context%</argument>
            <tag name="sulu.request_attributes" priority="-32"/>
        </service>
     * @var RequestAnalyzerInterface|null
        ?RequestAnalyzerInterface $requestAnalyzer,

        if (null !== $requestAnalyzer) {
            @trigger_deprecation('sulu/sulu', '2.4', 'The argument "%s" in class "%s" is deprecated and not longer required set `null` instead.', RequestAnalyzerInterface::class, __CLASS__);
        }

            <argument>null</argument>

<?php

/*
 * This file is part of Sulu.
 *
 * (c) Sulu GmbH
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace Sulu\Bundle\WebsiteBundle\EventListener;

use Sulu\Bundle\PageBundle\Document\BasePageDocument;
use Sulu\Component\Content\Compat\Structure\PageBridge;
use Sulu\Component\DocumentManager\Subscriber\EventSubscriberInterface;
use Sulu\Component\Security\Authorization\PermissionTypes;
use Sulu\Component\Security\Authorization\SecurityCheckerInterface;
use Sulu\Component\Security\Authorization\SecurityCondition;
use Sulu\Component\Webspace\Analyzer\Attributes\RequestAttributes;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;

class SecurityListener implements EventSubscriberInterface
{
    /**
     * @var SecurityCheckerInterface|null
     */
    private $securityChecker;

    public function __construct(
        ?SecurityCheckerInterface $securityChecker = null
    ) {
        $this->securityChecker = $securityChecker;
    }

    public static function getSubscribedEvents(): array
    {
        return [
            KernelEvents::REQUEST => [
                ['onKernelRequest', 7], // set the security listener after the firewall and after the routing listener
            ],
        ];
    }

    public function onKernelRequest(RequestEvent $event): void
    {
        $request = $event->getRequest();

        if (null === $this->securityChecker) {
            return;
        }

        $requestAttributes = $request->attributes->get('_sulu');
        if (!$requestAttributes instanceof RequestAttributes) {
            return;
        }

        $webspace = $requestAttributes->getAttribute('webspace');

        $structure = $request->attributes->get('structure');
        if (!$structure instanceof PageBridge) {
            return;
        }

        $document = $structure->getDocument();
        if (!$document instanceof BasePageDocument) {
            return;
        }

        if ($webspace->hasWebsiteSecurity()) {
            $this->securityChecker->checkPermission(
                new SecurityCondition(
                    'sulu.webspaces.' . $document->getWebspaceName(),
                    $document->getLocale(),
                    \get_class($document),
                    $document->getUuid()
                ),
                PermissionTypes::VIEW
            );
        }
    }
}
        <service id="sulu_website.event_listener.security_listener"
                 class="Sulu\Bundle\WebsiteBundle\EventListener\SecurityListener">
            <argument type="service" id="sulu_security.security_checker" on-invalid="null"/>

            <tag name="kernel.event_subscriber"/>
        </service>

            <argument>null</argument><!-- not longer required -->
use Webmozart\Assert\Assert;
        Assert::null($securityChecker, 'The security checker should be called by the SecurityListener not the ContentRouteProvider.'); // people who overwrite the ContentRouteProvider should make aware of that they also need to refactor this
use Symfony\Bundle\SecurityBundle\SecurityBundle;
    /**
     * @var string
     */
    private $appContext;

        $envParts = \explode('_', $environment, 2);
        $this->appContext = $envParts[1] ?? '';

        parent::__construct($envParts[0], $debug, $suluContext);
        if ('' !== $this->appContext) {
            $loader->load(__DIR__ . '/config/config_' . $this->appContext . '.yml');
        }
    }

    public function registerBundles(): iterable
    {
        $bundles = parent::registerBundles();

        if ('with_security' === $this->appContext) {
            $bundles[] = new SecurityBundle();
        }

        return $bundles;
    }

    /**
     * @return string
     */
    public function getCacheDir()
    {
        return parent::getCacheDir() . \ltrim('/' . $this->appContext);
    }

    /**
     * @return string
     */
    public function getCommonCacheDir()
    {
        return parent::getCommonCacheDir() . \ltrim('/' . $this->appContext);
security:
    enable_authenticator_manager: true

    access_decision_manager:
        strategy: unanimous
        allow_if_all_abstain: true

    # https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
    password_hashers:
        Sulu\Bundle\SecurityBundle\Entity\User: bcrypt

    # https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
    providers:
        sulu:
            id: sulu_security.user_provider

    firewalls:
        website:
            pattern: ^/
            lazy: true
            provider: sulu
            # The login and logout routes need to be created.
            # For an advanced user management with registration and opt-in emails have a look at the:
            # https://github.com/sulu/SuluCommunityBundle
            # Also have a look at the user context based caching when you output user role specific data
            # https://docs.sulu.io/en/2.2/cookbook/user-context-caching.html
            form_login:
                login_path: login
                check_path: login
            logout:
                path: logout
                target: /
            remember_me:
                secret:   "%kernel.secret%"
                lifetime: 604800 # 1 week in seconds
                path:     /

sulu_security:
    checker:
        enabled: true

login:
    path: /login
    controller:    Symfony\Bundle\FrameworkBundle\Controller\TemplateController
    defaults:
        template: login.html.twig
<?php

/*
 * This file is part of Sulu.
 *
 * (c) Sulu GmbH
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace Sulu\Bundle\WebsiteBundle\Tests\Functional;

use Sulu\Bundle\PageBundle\Document\BasePageDocument;
use Sulu\Bundle\PageBundle\Document\PageDocument;
use Sulu\Bundle\SecurityBundle\Entity\AccessControl;
use Sulu\Bundle\SecurityBundle\Entity\Permission;
use Sulu\Bundle\SecurityBundle\Entity\Role;
use Sulu\Bundle\TestBundle\Testing\SuluTestCase;
use Sulu\Bundle\WebsiteBundle\Tests\Application\Kernel;
use Sulu\Component\Content\Document\Behavior\SecurityBehavior;
use Sulu\Component\Content\Document\WorkflowStage;
use Symfony\Bundle\FrameworkBundle\KernelBrowser;

/**
 * @runTestsInSeparateProcesses This is necessary because the kernel is booted with different configurations.
 */
class SecurityListenerTest extends SuluTestCase
{
    /**
     * @var KernelBrowser
     */
    private $client;

    protected function setUp(): void
    {
        if (Kernel::VERSION_ID < 50000) { // @phpstan-ignore-line
            $this->markTestSkipped('This test is only for Symfony 5.0 and above');
        }

        $this->client = $this->createWebsiteClient(['environment' => 'test_with_security']);
        $this->purgeDatabase();
        $this->initPhpcr();
    }

    public function testNoPermissions(): void
    {
        $pageDocument = $this->createSecuredPage();

        $this->client->request('GET', 'http://sulu.lo/');
        $response = $this->client->getResponse();

        $this->assertSame(200, $response->getStatusCode());
        $this->assertNull($response->headers->get('Location'));
    }

    public function testRedirectToLoginWhenNoAccess(): void
    {
        $pageDocument = $this->createSecuredPage();

        $this->client->request('GET', 'http://sulu.lo/secure-area');
        $response = $this->client->getResponse();

        $this->assertSame(302, $response->getStatusCode());
        $this->assertSame('http://sulu.lo/login', $response->headers->get('Location'));
    }

    private function createSecuredPage(): BasePageDocument
    {
        $documentManager = $this->getContainer()->get('sulu_document_manager.document_manager');
        $entityManager = $this->getEntityManager();

        $pageData = [
            'locale' => 'en',
            'title' => 'Secure Area',
            'url' => '/secure-area',
            'article' => '<p>Some sample text for this super secret area.</p>',
            'structureType' => 'default',
        ];

        $extensionData = [
            'seo' => [],
            'excerpt' => [],
        ];

        /** @var PageDocument $pageDocument */
        $pageDocument = $documentManager->create('page');

        $pageDocument->setNavigationContexts([]);
        $pageDocument->setLocale($pageData['locale']);
        $pageDocument->setTitle($pageData['title']);
        $pageDocument->setResourceSegment($pageData['url']);
        $pageDocument->setStructureType($pageData['structureType']);
        $pageDocument->setWorkflowStage(WorkflowStage::PUBLISHED);
        $pageDocument->getStructure()->bind($pageData);
        $pageDocument->setAuthor(1);
        $pageDocument->setExtensionsData($extensionData);
        $pageDocument->setPermissions([
            1 => [ // do not allow anonymous users to access this page
                'view' => false,
            ],
        ]);

        $documentManager->persist(
            $pageDocument,
            'en',
            ['parent_path' => '/cmf/sulu_io/contents']
        );
        $documentManager->flush();

        // We need to add access control here as we do not have the document id before
        $role = new Role();
        $role->setName('Anonymous User Website');
        $role->setSystem('sulu_io');
        $role->setAnonymous(true);

        $permission = new Permission();
        $permission->setRole($role);
        $permission->setPermissions(127);
        $permission->setContext('sulu.webspaces.sulu_io');
        $role->addPermission($permission);

        $accessControl = new AccessControl();
        $accessControl->setPermissions(0);
        $accessControl->setEntityId($pageDocument->getUuid());
        $accessControl->setEntityClass(SecurityBehavior::class);
        $accessControl->setRole($role);

        $entityManager->persist($permission);
        $entityManager->persist($role);
        $entityManager->persist($accessControl);
        $entityManager->flush();

        $pageDocument->setPermissions([
            $role->getId() => [ // do not allow anonymous users to access this page
                'view' => false,
            ],
        ]);
        $documentManager->persist(
            $pageDocument,
            'en',
            ['parent_path' => '/cmf/sulu_io/contents']
        );
        $documentManager->flush();
        $documentManager->publish($pageDocument, 'en');

        $documentManager->clear();
        $entityManager->clear();

        return $pageDocument;
    }
}
<?php

/*
 * This file is part of Sulu.
 *
 * (c) Sulu GmbH
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace Sulu\Component\Webspace\Analyzer\Attributes;

use Sulu\Bundle\AdminBundle\Admin\Admin;
use Sulu\Bundle\SecurityBundle\System\SystemStoreInterface;
use Sulu\Component\HttpKernel\SuluKernel;
use Sulu\Component\Webspace\PortalInformation;
use Symfony\Component\HttpFoundation\Request;

/**
 * @internal
 * @final
 *
 * This class is internal overriding or extending should not be required instead create an own RequestProcessor.
 */
class SystemRequestProcessor implements RequestProcessorInterface
{
    /**
     * @var SystemStoreInterface
     */
    private $systemStore;

    /**
     * @var string
     */
    private $context;

    public function __construct(
        SystemStoreInterface $systemStore,
        string $context
    ) {
        $this->systemStore = $systemStore;
        $this->context = $context;
    }

    public function process(Request $request, RequestAttributes $requestAttributes)
    {
        $attributes = [];
        if (SuluKernel::CONTEXT_ADMIN === $this->context) {
            $this->systemStore->setSystem(Admin::SULU_ADMIN_SECURITY_SYSTEM);
            $attributes['system'] = Admin::SULU_ADMIN_SECURITY_SYSTEM;

            return new RequestAttributes($attributes);
        }
        $portalInformation = $requestAttributes->getAttribute('portalInformation');

        if (!$portalInformation instanceof PortalInformation) {
            return new RequestAttributes($attributes);
        }

        $webspace = $portalInformation->getWebspace();

        $security = $webspace->getSecurity();
        if ($security) {
            $attributes['system'] = $security->getSystem();
            $this->systemStore->setSystem($attributes['system']);
        }

        return new RequestAttributes($attributes);
    }

    public function validate(RequestAttributes $attributes)
    {
        return true;
    }
}