Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IBX-8140: Enabled authenticator manager-based security #368

Merged
Merged
Show file tree
Hide file tree
Changes from 13 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
17 changes: 17 additions & 0 deletions dependencies.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"recipesEndpoint": "https://api.github.com/repos/ibexa/recipes-dev/contents/index.json?ref=flex/pull-118",
"packages": [
{
"requirement": "dev-ibx-8140-enable-authorization-with-new-authenticator-mechanisms as 5.0.x-dev",
"repositoryUrl": "https://github.com/ibexa/rest",
"package": "ibexa/rest",
"shouldBeAddedAsVCS": false
},
{
"requirement": "dev-ibx-8140-enable-authorization-with-new-authenticator-mechanisms as 5.0.x-dev",
"repositoryUrl": "https://github.com/ibexa/admin-ui",
"package": "ibexa/admin-ui",
"shouldBeAddedAsVCS": false
}
]
}
222 changes: 1 addition & 221 deletions phpstan-baseline.neon

Large diffs are not rendered by default.

67 changes: 14 additions & 53 deletions src/bundle/Core/DependencyInjection/Compiler/SecurityPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,9 @@
namespace Ibexa\Bundle\Core\DependencyInjection\Compiler;

use Ibexa\Contracts\Core\Repository\PermissionResolver;
use Ibexa\Contracts\Core\Repository\UserService;
use Ibexa\Core\MVC\Symfony\Security\Authentication\AnonymousAuthenticationProvider;
use Ibexa\Core\MVC\Symfony\Security\Authentication\DefaultAuthenticationSuccessHandler;
use Ibexa\Core\MVC\Symfony\Security\Authentication\GuardRepositoryAuthenticationProvider;
use Ibexa\Core\MVC\Symfony\Security\Authentication\RememberMeRepositoryAuthenticationProvider;
use Ibexa\Core\MVC\Symfony\Security\Authentication\RepositoryAuthenticationProvider;
use Ibexa\Core\MVC\Symfony\Security\HttpUtils;
use Ibexa\Core\MVC\Symfony\SiteAccess;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
Expand All @@ -22,52 +19,24 @@

/**
* Security related compiler pass.
* Manipulates Symfony core security services to adapt them to eZ security needs.
* Manipulates Symfony core security services to adapt them to Ibexa security needs.
*/
class SecurityPass implements CompilerPassInterface
final class SecurityPass implements CompilerPassInterface
{
public const CONSTANT_AUTH_TIME_SETTING = 'ibexa.security.authentication.constant_auth_time';
public const string CONSTANT_AUTH_TIME_SETTING = 'ibexa.security.authentication.constant_auth_time';

public const CONSTANT_AUTH_TIME_DEFAULT = 1.0;
public const float CONSTANT_AUTH_TIME_DEFAULT = 1.0;

public function process(ContainerBuilder $container)
public function process(ContainerBuilder $container): void
{
if (!($container->hasDefinition('security.authentication.provider.dao') &&
$container->hasDefinition('security.authentication.provider.rememberme') &&
$container->hasDefinition('security.authentication.provider.guard') &&
$container->hasDefinition('security.authentication.provider.anonymous'))) {
if (
!$container->hasDefinition('security.authentication.provider.rememberme') ||
!$container->hasDefinition('security.authentication.provider.guard')
) {
return;
}

$configResolverRef = new Reference('ibexa.config.resolver');
$permissionResolverRef = new Reference(PermissionResolver::class);
$userServiceRef = new Reference(UserService::class);
$loggerRef = new Reference('logger');

// Override and inject the Repository in the authentication provider.
// We need it for checking user credentials
$daoAuthenticationProviderDef = $container->findDefinition('security.authentication.provider.dao');
$daoAuthenticationProviderDef->setClass(RepositoryAuthenticationProvider::class);
$daoAuthenticationProviderDef->addMethodCall(
'setPermissionResolver',
[$permissionResolverRef]
);
$daoAuthenticationProviderDef->addMethodCall(
'setUserService',
[$userServiceRef]
);
$daoAuthenticationProviderDef->addMethodCall(
'setConstantAuthTime',
[
$container->hasParameter(self::CONSTANT_AUTH_TIME_SETTING) ?
(float)$container->getParameter(self::CONSTANT_AUTH_TIME_SETTING) :
self::CONSTANT_AUTH_TIME_DEFAULT,
]
);
$daoAuthenticationProviderDef->addMethodCall(
'setLogger',
[$loggerRef]
);

$rememberMeAuthenticationProviderDef = $container->findDefinition('security.authentication.provider.rememberme');
$rememberMeAuthenticationProviderDef->setClass(RememberMeRepositoryAuthenticationProvider::class);
Expand All @@ -83,18 +52,6 @@ public function process(ContainerBuilder $container)
[$permissionResolverRef]
);

$anonymousAuthenticationProviderDef = $container->findDefinition('security.authentication.provider.anonymous');
$anonymousAuthenticationProviderDef->setClass(AnonymousAuthenticationProvider::class);
$anonymousAuthenticationProviderDef->addMethodCall(
'setPermissionResolver',
[$permissionResolverRef]
);

$anonymousAuthenticationProviderDef->addMethodCall(
'setConfigResolver',
[$configResolverRef]
);

if (!$container->hasDefinition('security.http_utils')) {
return;
}
Expand All @@ -114,11 +71,15 @@ public function process(ContainerBuilder $container)
$successHandlerDef->setClass(DefaultAuthenticationSuccessHandler::class);
$successHandlerDef->addMethodCall(
'setConfigResolver',
[$configResolverRef]
[new Reference('ibexa.config.resolver')]
konradoboza marked this conversation as resolved.
Show resolved Hide resolved
);
$successHandlerDef->addMethodCall(
'setEventDispatcher',
[new Reference('event_dispatcher')]
);
$successHandlerDef->addMethodCall(
'setPermissionResolver',
[$permissionResolverRef]
);
}
}
23 changes: 0 additions & 23 deletions src/bundle/Core/DependencyInjection/Security/HttpBasicFactory.php

This file was deleted.

1 change: 1 addition & 0 deletions src/bundle/Core/Features/Content/content_preview.feature
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@javascript
konradoboza marked this conversation as resolved.
Show resolved Hide resolved
Feature: Preview of content drafts

As a content editor
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@javascript
Feature: Handling of Unauthorized repository exceptions
Scenario: When a Repository UnauthorizedException is throw, anonymous users are shown the login screen
Given that I am not logged in
Expand Down
11 changes: 5 additions & 6 deletions src/bundle/Core/IbexaCoreBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Bundle\Core;

Expand Down Expand Up @@ -37,7 +38,6 @@
use Ibexa\Bundle\Core\DependencyInjection\Configuration\Parser as ConfigParser;
use Ibexa\Bundle\Core\DependencyInjection\Configuration\Parser\Repository as RepositoryConfigParser;
use Ibexa\Bundle\Core\DependencyInjection\IbexaCoreExtension;
use Ibexa\Bundle\Core\DependencyInjection\Security\HttpBasicFactory;
use Ibexa\Contracts\Core\MVC\View\VariableProvider;
use Ibexa\Core\Base\Container\Compiler\FieldTypeRegistryPass;
use Ibexa\Core\Base\Container\Compiler\GenericFieldTypeConverterPass;
Expand All @@ -49,11 +49,12 @@
use Ibexa\Core\Base\Container\Compiler\Storage\Legacy\RoleLimitationConverterPass;
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
use Symfony\Component\HttpKernel\Bundle\Bundle;

class IbexaCoreBundle extends Bundle
final class IbexaCoreBundle extends Bundle
{
public function build(ContainerBuilder $container)
public function build(ContainerBuilder $container): void
{
parent::build($container);
$container->addCompilerPass(new GenericFieldTypeConverterPass(), PassConfig::TYPE_OPTIMIZE);
Expand Down Expand Up @@ -92,15 +93,13 @@ public function build(ContainerBuilder $container)
$container->addCompilerPass(new RoleLimitationConverterPass());
$container->addCompilerPass(new QueryTypePass());

$securityExtension = $container->getExtension('security');
$securityExtension->addSecurityListenerFactory(new HttpBasicFactory());
$container->addCompilerPass(new TranslationCollectorPass());
$container->addCompilerPass(new SlugConverterConfigurationPass());

$container->registerForAutoconfiguration(VariableProvider::class)->addTag('ezplatform.view.variable_provider');
}

public function getContainerExtension()
public function getContainerExtension(): ?ExtensionInterface
{
if (!isset($this->extension)) {
$this->extension = new IbexaCoreExtension(
Expand Down
17 changes: 4 additions & 13 deletions src/bundle/Core/Resources/config/security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,10 @@ services:
class: Ibexa\Core\MVC\Symfony\Controller\SecurityController
arguments: ["@twig", '@ibexa.config.resolver', "@security.authentication_utils"]

Ibexa\Core\MVC\Symfony\Security\EventListener\SecurityListener:
class: Ibexa\Core\MVC\Symfony\Security\EventListener\SecurityListener
arguments:
- '@Ibexa\Contracts\Core\Repository\PermissionResolver'
- '@Ibexa\Contracts\Core\Repository\UserService'
- '@ibexa.config.resolver'
- "@event_dispatcher"
- "@security.token_storage"
- "@security.authorization_checker"
- "%fragment.path%"
tags:
- { name: kernel.event_subscriber }

ibexa.security.user_provider: '@Ibexa\Core\MVC\Symfony\Security\User\UsernameProvider'
ibexa.security.user_provider.username: '@Ibexa\Core\MVC\Symfony\Security\User\UsernameProvider'
ibexa.security.user_provider.email: '@Ibexa\Core\MVC\Symfony\Security\User\EmailProvider'

Ibexa\Core\MVC\Symfony\Security\Authentication\EventSubscriber\AccessDeniedSubscriber:
autowire: true
autoconfigure: true
Empty file removed src/lib/.gitkeep
Empty file.

This file was deleted.

konradoboza marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,27 @@
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Core\MVC\Symfony\Security\Authentication;

use Ibexa\Contracts\Core\Repository\PermissionResolver;
use Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface;
use Ibexa\Core\MVC\Symfony\Security\UserInterface;
use Psr\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Http\Authentication\DefaultAuthenticationSuccessHandler as BaseSuccessHandler;

class DefaultAuthenticationSuccessHandler extends BaseSuccessHandler
final class DefaultAuthenticationSuccessHandler extends BaseSuccessHandler
{
private EventDispatcherInterface $eventDispatcher;

private ConfigResolverInterface $configResolver;

/**
* Injects the ConfigResolver to potentially override default_target_path for redirections after authentication success.
*/
private PermissionResolver $permissionResolver;

public function setConfigResolver(ConfigResolverInterface $configResolver): void
{
$this->configResolver = $configResolver;
Expand All @@ -31,20 +35,42 @@ public function setEventDispatcher(EventDispatcherInterface $eventDispatcher): v
$this->eventDispatcher = $eventDispatcher;
}

protected function determineTargetUrl(Request $request)
public function setPermissionResolver(PermissionResolver $permissionResolver): void
{
$this->permissionResolver = $permissionResolver;
}

public function onAuthenticationSuccess(Request $request, TokenInterface $token): ?Response
{
$user = $token->getUser();
if ($user instanceof UserInterface && isset($this->permissionResolver)) {
$this->permissionResolver->setCurrentUserReference($user->getAPIUser());
}

return parent::onAuthenticationSuccess($request, $token);
}

protected function determineTargetUrl(Request $request): string
{
if (isset($this->configResolver)) {
$defaultPage = $this->configResolver->getParameter('default_page');
if ($defaultPage !== null) {
$this->options['default_target_path'] = $defaultPage;
$this->setOptions([
'default_target_path' => $defaultPage,
]);
}
}

if (isset($this->eventDispatcher)) {
$event = new DetermineTargetUrlEvent($request, $this->options, $this->getFirewallName());
$event = new DetermineTargetUrlEvent(
$request,
$this->getOptions(),
$this->getFirewallName() ?? ''
);

$this->eventDispatcher->dispatch($event);

$this->options = $event->getOptions();
$this->setOptions($event->getOptions());
}

return parent::determineTargetUrl($request);
Expand Down
Loading
Loading