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
3 changes: 3 additions & 0 deletions .php-cs-fixer.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,5 +101,8 @@
'simplified_null_return' => true,
'single_line_empty_body' => true,
'static_lambda' => true,

// PhpUnit rules
'php_unit_strict' => false,
])
;
7 changes: 6 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,12 @@
"require-dev": {
"doctrine/orm": "^2.3 || ^3",
"symfony/event-dispatcher": "^6.4",
"symfony/phpunit-bridge": "^6.4"
"symfony/phpunit-bridge": "^6.4",
"symfony/test-pack": "^1.2",
"phpstan/phpstan": "^2.1",
"vimeo/psalm": "^6.13",
"friendsofphp/php-cs-fixer": "^3.84",
"psalm/plugin-symfony": "^5.2"
},
"autoload": {
"psr-4": {
Expand Down
8 changes: 8 additions & 0 deletions phpstan.dist.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
parameters:
level: 8
paths:
- src/
- tests/
excludePaths:
- src/DependencyInjection/Configuration.php
- src/DependencyInjection/Security/UserProvider/SamlUserProviderFactory.php
10 changes: 0 additions & 10 deletions phpstan.neon

This file was deleted.

6 changes: 4 additions & 2 deletions psalm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@
<ignoreFiles>
<file name="src/DependencyInjection/Configuration.php" />
<file name="src/DependencyInjection/Security/UserProvider/SamlUserProviderFactory.php" />
<file name="vendor/symfony/security-http/Authentication/DefaultAuthenticationSuccessHandler.php" />
<directory name="vendor" />
</ignoreFiles>
</projectFiles>

<plugins>
<pluginClass class="Psalm\SymfonyPsalmPlugin\Plugin" />
</plugins>
<issueHandlers>
<ClassMustBeFinal errorLevel="info" />
</issueHandlers>
</psalm>
29 changes: 19 additions & 10 deletions src/Controller/Login.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

use Nbgrp\OneloginSamlBundle\Security\Http\Authenticator\SamlAuthenticator;
use OneLogin\Saml2\Auth;
use OneLogin\Saml2\Error as Saml2Exception;
use Symfony\Bundle\SecurityBundle\Security\FirewallMap;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
Expand All @@ -16,10 +17,10 @@
use Symfony\Component\Security\Http\SecurityRequestAttributes;

#[AsController]
class Login
readonly class Login
{
public function __construct(
private readonly FirewallMap $firewallMap,
private FirewallMap $firewallMap,
) {}

public function __invoke(Request $request, Auth $auth): RedirectResponse
Expand All @@ -44,30 +45,38 @@ public function __invoke(Request $request, Auth $auth): RedirectResponse
throw new \RuntimeException($error->getMessage());
}

return new RedirectResponse($this->processLoginAndGetRedirectUrl($auth, $targetPath, $session));
try {
return new RedirectResponse($this->processLoginAndGetRedirectUrl($auth, $targetPath, $session));
} catch (Saml2Exception $e) {
throw new \RuntimeException($e->getMessage());
}
}

/** @psalm-suppress MixedInferredReturnType, MixedReturnStatement */
private function getTargetPath(Request $request, SessionInterface $session): ?string
{
$firewallName = $this->firewallMap->getFirewallConfig($request)?->getName();
if (!$firewallName) {
if (null === $firewallName || '' === $firewallName) {
throw new ServiceUnavailableHttpException(message: 'Unknown firewall.');
}

/** @phpstan-ignore-next-line */
return $session->get('_security.'.$firewallName.'.target_path');
$attribute = (string) $session->get('_security.'.$firewallName.'.target_path');

return ($attribute === '') ? null : $attribute;
}

/**
* @throws Saml2Exception
*/
private function processLoginAndGetRedirectUrl(Auth $auth, ?string $targetPath, ?SessionInterface $session): string
{
/** @var string|null $redirectUrl */
$redirectUrl = $auth->login(returnTo: $targetPath, stay: true);
if ($redirectUrl === null) {
throw new \RuntimeException('Login cannot be performed: Auth did not returned redirect url.');
if (null === $redirectUrl) {
throw new \RuntimeException('Unable to initiate SAML login process.');
}

$security = $auth->getSettings()->getSecurityData();
if (($security['rejectUnsolicitedResponsesWithInResponseTo'] ?? false) && $session instanceof SessionInterface) {
if ((($security['rejectUnsolicitedResponsesWithInResponseTo'] ?? false) === true) && $session instanceof SessionInterface) {
$session->set(SamlAuthenticator::LAST_REQUEST_ID, $auth->getLastRequestID());
}

Expand Down
2 changes: 1 addition & 1 deletion src/Controller/Logout.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
use Symfony\Component\HttpKernel\Attribute\AsController;

#[AsController]
class Logout
readonly class Logout
{
public function __invoke(): void
{
Expand Down
6 changes: 5 additions & 1 deletion src/Controller/Metadata.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@
namespace Nbgrp\OneloginSamlBundle\Controller;

use OneLogin\Saml2\Auth;
use OneLogin\Saml2\Error as Saml2Exception;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;

#[AsController]
class Metadata
readonly class Metadata
{
/**
* @throws Saml2Exception
*/
public function __invoke(Auth $auth): Response
{
return new Response(
Expand Down
31 changes: 26 additions & 5 deletions src/DependencyInjection/Compiler/AuthRegistryCompilerPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/
class AuthRegistryCompilerPass implements CompilerPassInterface
{
#[\Override]
public function process(ContainerBuilder $container): void
{
$authRegistry = $container->getDefinition(AuthRegistryInterface::class);
Expand All @@ -27,11 +28,31 @@ public function process(ContainerBuilder $container): void
throw new \UnexpectedValueException('OneLogin settings should be an array.');
}

/** @var array $settings */
foreach ($oneloginSettings as $key => $settings) {
$authDefinition = new Definition(Auth::class, [$settings]);
$authDefinition->setFactory(new Reference(AuthFactory::class));
$authRegistry->addMethodCall('addService', [$key, $authDefinition]);
/** @var array<string,mixed> $idpSettings */
foreach ($oneloginSettings as $idpKey => $idpSettings) {
/** @var array<string, mixed> $settings */
$settings = $idpSettings;
if (isset($idpSettings['sp'])) {
if (!\is_array($idpSettings['sp'])) {
throw new \UnexpectedValueException('OneLogin SP settings should be an array.');
}
/** @var array<string,mixed>|null $spSettings */
foreach ($idpSettings['sp'] as $spKey => $spSettings) {
if (!\is_array($spSettings)) {
throw new \UnexpectedValueException('OneLogin SP settings for key "'.(string) $spKey.'" should be an array.');
}

$settings['sp'] = $spSettings;
$authDefinition = new Definition(Auth::class, [$settings]);
$authDefinition->setFactory(new Reference(AuthFactory::class));
$authRegistry->addMethodCall('addService', [$idpKey, $spKey, $authDefinition]);
}
} else {
$settings['sp'] = 'default';
$authDefinition = new Definition(Auth::class, [$settings]);
$authDefinition->setFactory(new Reference(AuthFactory::class));
$authRegistry->addMethodCall('addService', [$idpKey, 'default', $authDefinition]);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
*/
class EntityManagerCompilerPass implements CompilerPassInterface
{
#[\Override]
public function process(ContainerBuilder $container): void
{
if (!$container->hasParameter('nbgrp_onelogin_saml.entity_manager')) {
Expand Down
1 change: 1 addition & 0 deletions src/DependencyInjection/Compiler/ProxyVarsCompilerPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
*/
class ProxyVarsCompilerPass implements CompilerPassInterface
{
#[\Override]
public function process(ContainerBuilder $container): void
{
$useProxyVars = $container->getParameter('nbgrp_onelogin_saml.use_proxy_vars');
Expand Down
Loading
Loading