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
16 changes: 8 additions & 8 deletions .github/workflows/audit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,21 @@ jobs:
name: Audit
strategy:
matrix:
php-version: [ '8.1', '8.2', '8.3' ]
php-version: [ '8.1', '8.2', '8.3', '8.4' ]
fail-fast: false
runs-on: ubuntu-latest
steps:
- name: Checkout (Push)
uses: actions/checkout@v4
uses: actions/checkout@v5
if: github.event_name == 'push'
with:
fetch-depth: 0

- name: Checkout (PR)
uses: actions/checkout@v4
uses: actions/checkout@v5
if: github.event_name == 'pull_request'
with:
ref: ${{ github.event.pull_request.head.ref }}
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0

- name: Setup PHP
Expand All @@ -38,7 +38,7 @@ jobs:
run: echo "DIR=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT

- name: Cache dependencies
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.DIR }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
Expand All @@ -54,13 +54,13 @@ jobs:
echo "::endgroup::"

- name: Auditor
uses: docker://nbgrp/auditor:0.21.0
uses: docker://nbgrp/auditor:0.31.0

- name: Tests
run: vendor/bin/simple-phpunit
run: SYMFONY_DEPRECATIONS_HELPER="max[total]=11&max[direct]=0&max[indirect]=0&max[self]=1" vendor/bin/simple-phpunit

- name: Codecov
uses: codecov/codecov-action@v3
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./clover.xml
19 changes: 15 additions & 4 deletions .php-cs-fixer.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,31 @@
'src/DependencyInjection/Configuration.php',
'src/DependencyInjection/Security/UserProvider/SamlUserProviderFactory.php',
'src/Resources/config/services.php',
])
]),
)
->setRiskyAllowed(true)
->setRules([
// base presets
'@PER' => true,
'@PER-CS' => true,
'@PhpCsFixer' => true,
'@Symfony' => true,
'@PHP81Migration' => true,

// risky presets
'@PER:risky' => true,
'@PER-CS:risky' => true,
'@PhpCsFixer:risky' => true,
'@Symfony:risky' => true,
'@PHP80Migration:risky' => true,

// presets tuning
'blank_line_after_opening_tag' => false,
'blank_line_before_statement' => [
'statements' => ['case', 'default', 'return', 'throw', 'try'],
'statements' => ['case', 'default', 'declare', 'return', 'throw', 'try'],
],
'comment_to_phpdoc' => [
'ignored_tags' => [
'phan-suppress-current-line',
'phan-suppress-next-line',
'see',
'todo',
],
Expand Down Expand Up @@ -74,6 +76,15 @@
'function',
],
],
'php_unit_data_provider_static' => false,
'php_unit_test_case_static_method_calls' => false,
'phpdoc_order' => [
'order' => [
'param',
'throws',
'return',
],
],
'phpdoc_separation' => false,
'phpdoc_summary' => false,
'phpdoc_to_comment' => false,
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ nbgrp_onelogin_saml:
wantNameId: false
wantNameIdEncrypted: false
requestedAuthnContext: true
requestedAuthnContextComparison: 'exact'
wantXMLValidation: false
relaxDestinationValidation: false
destinationStrictlyMatches: true
Expand Down
11 changes: 7 additions & 4 deletions phpcs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,10 @@
<property name="modifiersOrder" type="array">
<element value="var" />
<element value="public, protected, private" />
<element value="static" />
<element value="static, readonly" />
</property>
<property name="checkPromoted" value="true" />
<property name="enableMultipleSpacesBetweenModifiersCheck" value="true" />
</properties>
</rule>
<rule ref="SlevomatCodingStandard.Classes.RequireConstructorPropertyPromotion" />
Expand Down Expand Up @@ -183,14 +185,15 @@

<rule ref="SlevomatCodingStandard.TypeHints.DeclareStrictTypes">
<properties>
<property name="linesCountBeforeDeclare" value="0" />
<property name="linesCountAfterDeclare" value="1" />
<property name="spacesCountAroundEqualsSign" value="0" />
</properties>
</rule>
<rule ref="SlevomatCodingStandard.TypeHints.DisallowArrayTypeHintSyntax">
<properties>
<property name="traversableTypeHints" value="true" />
<property name="traversableTypeHints" type="array">
<element value="\ArrayIterator" />
<element value="\Traversable" />
</property>
</properties>
</rule>
<rule ref="SlevomatCodingStandard.TypeHints.NullableTypeForNullDefaultValue" />
Expand Down
11 changes: 7 additions & 4 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ parameters:
paths:
- src
- tests
bootstrapFiles:
- vendor/bin/.phpunit/phpunit/vendor/autoload.php

checkMissingIterableValueType: false
checkGenericClassInNonGenericObjectType: false
treatPhpDocTypesAsCertain: false

ignoreErrors:
-
identifier: missingType.iterableValue
-
identifier: missingType.generics
1 change: 0 additions & 1 deletion phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
<php>
<ini name="error_reporting" value="-1" />
<server name="SYMFONY_PHPUNIT_VERSION" value="9.5" />
<env name="SYMFONY_DEPRECATIONS_HELPER" value="max[indirect]=1" />
</php>

<testsuites>
Expand Down
9 changes: 9 additions & 0 deletions psalm.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?xml version="1.0"?>
<psalm
errorLevel="1"
phpVersion="8.1"
strictBinaryOperands="true"
findUnusedPsalmSuppress="true"
sealAllMethods="true"
Expand All @@ -17,6 +18,14 @@
</ignoreFiles>
</projectFiles>

<issueHandlers>
<ClassMustBeFinal>
<errorLevel type="suppress">
<directory name="src" />
</errorLevel>
</ClassMustBeFinal>
</issueHandlers>

<plugins>
<pluginClass class="Psalm\SymfonyPsalmPlugin\Plugin" />
</plugins>
Expand Down
10 changes: 4 additions & 6 deletions src/Controller/Login.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@ public function __invoke(Request $request, Auth $auth): RedirectResponse
return new RedirectResponse($this->processLoginAndGetRedirectUrl($auth, $targetPath, $session));
}

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

Expand All @@ -62,15 +62,13 @@ private function getTargetPath(Request $request, SessionInterface $session): ?st
private function processLoginAndGetRedirectUrl(Auth $auth, ?string $targetPath, ?SessionInterface $session): string
{
$redirectUrl = $auth->login(returnTo: $targetPath, stay: true);
if ($redirectUrl === null) {
throw new \RuntimeException('Login cannot be performed: Auth did not returned redirect url.');
}

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

// @phan-suppress-next-line PhanPossiblyNullTypeReturn
return $redirectUrl;
}
}
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 Down
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
27 changes: 18 additions & 9 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public function getConfigTreeBuilder(): TreeBuilder
$rootNode = $treeBuilder->getRootNode();

// @formatter:off
/** @phpstan-ignore-next-line */
// @phpstan-ignore-next-line
$rootNode
->info('nb:group OneLogin PHP Symfony Bundle configuration')
->children()
Expand Down Expand Up @@ -51,7 +51,7 @@ public function getConfigTreeBuilder(): TreeBuilder
->end()
->scalarNode('binding')
->validate()
->ifTrue(static fn ($value): bool => !str_starts_with($value, 'urn:oasis:names:tc:SAML:2.0:bindings:'))
->ifTrue(static fn ($value): bool => !str_starts_with((string) $value, 'urn:oasis:names:tc:SAML:2.0:bindings:'))
->thenInvalid('invalid value.')
->end()
->end()
Expand All @@ -63,7 +63,7 @@ public function getConfigTreeBuilder(): TreeBuilder
->scalarNode('responseUrl')->end()
->scalarNode('binding')
->validate()
->ifTrue(static fn ($value): bool => !str_starts_with($value, 'urn:oasis:names:tc:SAML:2.0:bindings:'))
->ifTrue(static fn ($value): bool => !str_starts_with((string) $value, 'urn:oasis:names:tc:SAML:2.0:bindings:'))
->thenInvalid('invalid value.')
->end()
->end()
Expand Down Expand Up @@ -100,7 +100,7 @@ public function getConfigTreeBuilder(): TreeBuilder
->end()
->scalarNode('binding')
->validate()
->ifTrue(static fn ($value): bool => !str_starts_with($value, 'urn:oasis:names:tc:SAML:2.0:bindings:'))
->ifTrue(static fn ($value): bool => !str_starts_with((string) $value, 'urn:oasis:names:tc:SAML:2.0:bindings:'))
->thenInvalid('invalid value.')
->end()
->end()
Expand Down Expand Up @@ -133,15 +133,15 @@ public function getConfigTreeBuilder(): TreeBuilder
->end()
->scalarNode('binding')
->validate()
->ifTrue(static fn ($value): bool => !str_starts_with($value, 'urn:oasis:names:tc:SAML:2.0:bindings:'))
->ifTrue(static fn ($value): bool => !str_starts_with((string) $value, 'urn:oasis:names:tc:SAML:2.0:bindings:'))
->thenInvalid('invalid value.')
->end()
->end()
->end()
->end()
->scalarNode('NameIDFormat')
->validate()
->ifTrue(static fn ($value): bool => !(str_starts_with($value, 'urn:oasis:names:tc:SAML:1.1:nameid-format:') || str_starts_with($value, 'urn:oasis:names:tc:SAML:2.0:nameid-format:')))
->ifTrue(static fn ($value): bool => !(str_starts_with((string) $value, 'urn:oasis:names:tc:SAML:1.1:nameid-format:') || str_starts_with((string) $value, 'urn:oasis:names:tc:SAML:2.0:nameid-format:')))
->thenInvalid('invalid value.')
->end()
->end()
Expand Down Expand Up @@ -174,10 +174,19 @@ public function getConfigTreeBuilder(): TreeBuilder
->thenInvalid('must be an array or a boolean.')
->end()
->validate()
->ifTrue(static fn ($value) => \is_array($value) && array_filter($value, static fn ($item): bool => !str_starts_with($item, 'urn:oasis:names:tc:SAML:2.0:ac:classes:')))
// @phpstan-ignore-next-line
->ifTrue(static fn ($value) => \is_array($value) && array_filter($value, static fn ($item): bool => !str_starts_with((string) $item, 'urn:oasis:names:tc:SAML:2.0:ac:classes:')))
->thenInvalid('invalid value.')
->end()
->end()
->enumNode('requestedAuthnContextComparison')
->values([
'exact',
'minimum',
'maximum',
'better',
])
->end()
->booleanNode('wantXMLValidation')->end()
->booleanNode('relaxDestinationValidation')->end()
->booleanNode('destinationStrictlyMatches')->end()
Expand Down Expand Up @@ -285,8 +294,8 @@ public function getConfigTreeBuilder(): TreeBuilder
->end()
->end()
->validate()
->ifTrue(static fn ($value): bool => empty($value['organization']))
->then(static fn ($value): array => array_diff_key($value, ['organization' => null]))
->ifTrue(static fn (array $value): bool => empty($value['organization']))
->then(static fn (array $value): array => array_diff_key($value, ['organization' => null]))
->end()
->end()
->end()
Expand Down
1 change: 1 addition & 0 deletions src/DependencyInjection/NbgrpOneloginSamlExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
class NbgrpOneloginSamlExtension extends Extension
{
/** @psalm-suppress MixedArgument */
#[\Override]
public function load(array $configs, ContainerBuilder $container): void
{
$loader = new PhpFileLoader($container, new FileLocator(\dirname(__DIR__).'/Resources/config'));
Expand Down
3 changes: 3 additions & 0 deletions src/DependencyInjection/Security/Factory/SamlFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,20 @@ public function __construct()
$this->addOption('success_handler', SamlAuthenticationSuccessHandler::class);
}

#[\Override]
public function getPriority(): int
{
return self::PRIORITY;
}

#[\Override]
public function getKey(): string
{
return 'saml';
}

/** @psalm-suppress MixedArgument */
#[\Override]
public function createAuthenticator(ContainerBuilder $container, string $firewallName, array $config, string $userProviderId): string
{
$authenticatorId = 'security.authenticator.saml.'.$firewallName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

class SamlUserProviderFactory implements UserProviderFactoryInterface
{
#[\Override]
public function create(ContainerBuilder $container, string $id, array $config): void
{
$container
Expand All @@ -23,6 +24,7 @@ public function create(ContainerBuilder $container, string $id, array $config):
;
}

#[\Override]
public function getKey(): string
{
return 'saml';
Expand All @@ -31,17 +33,18 @@ public function getKey(): string
/**
* @suppress PhanUndeclaredMethod
*/
#[\Override]
public function addConfiguration(NodeDefinition $builder): void
{
// @formatter:off
/** @phpstan-ignore-next-line */
// @phpstan-ignore-next-line
$builder
->children()
->scalarNode('user_class')
->isRequired()
->cannotBeEmpty()
->validate()
->ifTrue(static fn ($value) => !is_a($value, UserInterface::class, true))
->ifTrue(static fn ($value) => !is_a((string) $value, UserInterface::class, true))
->thenInvalid('You should provide user class implementing '.UserInterface::class.' interface.')
->end()
->end()
Expand Down
Loading