Skip to content

Commit 478be78

Browse files
committed
Refactor Symfony test configurations and add badge support
Reorganized test configurations by splitting `config.yml` into `common.yml` and added Twig template support. Introduced Webauthn authentication mechanism with related classes, functional tests, and templates to enhance security. This commit also includes tests for authenticated access and successful login handling.
1 parent a05dc1a commit 478be78

32 files changed

+1017
-142
lines changed

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@
119119
"symfony/filesystem": "^6.4|^7.0",
120120
"symfony/finder": "^6.4|^7.0",
121121
"symfony/monolog-bundle": "^3.8",
122+
"symfony/twig-bundle": "^6.4|^7.0",
122123
"symfony/var-dumper": "^6.4|^7.0",
123124
"symfony/yaml": "^6.4|^7.0",
124125
"symplify/easy-coding-standard": "^12.0",

phpstan-baseline.neon

Lines changed: 165 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ parameters:
418418
path: src/symfony/src/DependencyInjection/WebauthnExtension.php
419419

420420
-
421-
message: '#^Method Webauthn\\Bundle\\Doctrine\\Type\\AttestedCredentialDataType\:\:convertToDatabaseValue\(\) should return string\|null but returns mixed\.$#'
421+
message: '#^Method Webauthn\\Bundle\\Doctrine\\Type\\AttestedCredentialDataType\:\:convertToDatabaseValue\(\) should return string\|null but returns T of mixed\.$#'
422422
identifier: return.type
423423
count: 1
424424
path: src/symfony/src/Doctrine/Type/AttestedCredentialDataType.php
@@ -436,7 +436,7 @@ parameters:
436436
path: src/symfony/src/Doctrine/Type/AttestedCredentialDataType.php
437437

438438
-
439-
message: '#^Method Webauthn\\Bundle\\Doctrine\\Type\\PublicKeyCredentialDescriptorType\:\:convertToDatabaseValue\(\) should return string\|null but returns mixed\.$#'
439+
message: '#^Method Webauthn\\Bundle\\Doctrine\\Type\\PublicKeyCredentialDescriptorType\:\:convertToDatabaseValue\(\) should return string\|null but returns T of mixed\.$#'
440440
identifier: return.type
441441
count: 1
442442
path: src/symfony/src/Doctrine/Type/PublicKeyCredentialDescriptorType.php
@@ -454,7 +454,7 @@ parameters:
454454
path: src/symfony/src/Doctrine/Type/PublicKeyCredentialDescriptorType.php
455455

456456
-
457-
message: '#^Method Webauthn\\Bundle\\Doctrine\\Type\\TrustPathDataType\:\:convertToDatabaseValue\(\) should return string\|null but returns mixed\.$#'
457+
message: '#^Method Webauthn\\Bundle\\Doctrine\\Type\\TrustPathDataType\:\:convertToDatabaseValue\(\) should return string\|null but returns T of mixed\.$#'
458458
identifier: return.type
459459
count: 1
460460
path: src/symfony/src/Doctrine/Type/TrustPathDataType.php
@@ -561,6 +561,168 @@ parameters:
561561
count: 1
562562
path: src/symfony/src/Security/Authentication/Token/WebauthnToken.php
563563

564+
-
565+
message: '#^Access to an undefined property Webauthn\\AuthenticatorResponse\:\:\$attestationObject\.$#'
566+
identifier: property.notFound
567+
count: 1
568+
path: src/symfony/src/Security/Authentication/WebauthnAuthenticator.php
569+
570+
-
571+
message: '#^Cannot access property \$authData on mixed\.$#'
572+
identifier: property.nonObject
573+
count: 1
574+
path: src/symfony/src/Security/Authentication/WebauthnAuthenticator.php
575+
576+
-
577+
message: '#^Cannot access property \$extensions on mixed\.$#'
578+
identifier: property.nonObject
579+
count: 1
580+
path: src/symfony/src/Security/Authentication/WebauthnAuthenticator.php
581+
582+
-
583+
message: '#^Cannot access property \$signCount on mixed\.$#'
584+
identifier: property.nonObject
585+
count: 1
586+
path: src/symfony/src/Security/Authentication/WebauthnAuthenticator.php
587+
588+
-
589+
message: '#^Cannot call method getReservedForFutureUse1\(\) on mixed\.$#'
590+
identifier: method.nonObject
591+
count: 1
592+
path: src/symfony/src/Security/Authentication/WebauthnAuthenticator.php
593+
594+
-
595+
message: '#^Cannot call method getReservedForFutureUse2\(\) on mixed\.$#'
596+
identifier: method.nonObject
597+
count: 1
598+
path: src/symfony/src/Security/Authentication/WebauthnAuthenticator.php
599+
600+
-
601+
message: '#^Cannot call method isBackedUp\(\) on mixed\.$#'
602+
identifier: method.nonObject
603+
count: 1
604+
path: src/symfony/src/Security/Authentication/WebauthnAuthenticator.php
605+
606+
-
607+
message: '#^Cannot call method isBackupEligible\(\) on mixed\.$#'
608+
identifier: method.nonObject
609+
count: 1
610+
path: src/symfony/src/Security/Authentication/WebauthnAuthenticator.php
611+
612+
-
613+
message: '#^Cannot call method isUserPresent\(\) on mixed\.$#'
614+
identifier: method.nonObject
615+
count: 1
616+
path: src/symfony/src/Security/Authentication/WebauthnAuthenticator.php
617+
618+
-
619+
message: '#^Cannot call method isUserVerified\(\) on mixed\.$#'
620+
identifier: method.nonObject
621+
count: 1
622+
path: src/symfony/src/Security/Authentication/WebauthnAuthenticator.php
623+
624+
-
625+
message: '#^Parameter \#12 \$isBackupEligible of class Webauthn\\Bundle\\Security\\Authentication\\Token\\WebauthnToken constructor expects bool, mixed given\.$#'
626+
identifier: argument.type
627+
count: 1
628+
path: src/symfony/src/Security/Authentication/WebauthnAuthenticator.php
629+
630+
-
631+
message: '#^Parameter \#13 \$isBackedUp of class Webauthn\\Bundle\\Security\\Authentication\\Token\\WebauthnToken constructor expects bool, mixed given\.$#'
632+
identifier: argument.type
633+
count: 1
634+
path: src/symfony/src/Security/Authentication/WebauthnAuthenticator.php
635+
636+
-
637+
message: '#^Parameter \#4 \$isUserPresent of class Webauthn\\Bundle\\Security\\Authentication\\Token\\WebauthnToken constructor expects bool, mixed given\.$#'
638+
identifier: argument.type
639+
count: 1
640+
path: src/symfony/src/Security/Authentication/WebauthnAuthenticator.php
641+
642+
-
643+
message: '#^Parameter \#5 \$isUserVerified of class Webauthn\\Bundle\\Security\\Authentication\\Token\\WebauthnToken constructor expects bool, mixed given\.$#'
644+
identifier: argument.type
645+
count: 1
646+
path: src/symfony/src/Security/Authentication/WebauthnAuthenticator.php
647+
648+
-
649+
message: '#^Parameter \#6 \$reservedForFutureUse1 of class Webauthn\\Bundle\\Security\\Authentication\\Token\\WebauthnToken constructor expects int, mixed given\.$#'
650+
identifier: argument.type
651+
count: 1
652+
path: src/symfony/src/Security/Authentication/WebauthnAuthenticator.php
653+
654+
-
655+
message: '#^Parameter \#7 \$reservedForFutureUse2 of class Webauthn\\Bundle\\Security\\Authentication\\Token\\WebauthnToken constructor expects int, mixed given\.$#'
656+
identifier: argument.type
657+
count: 1
658+
path: src/symfony/src/Security/Authentication/WebauthnAuthenticator.php
659+
660+
-
661+
message: '#^Parameter \#8 \$signCount of class Webauthn\\Bundle\\Security\\Authentication\\Token\\WebauthnToken constructor expects int, mixed given\.$#'
662+
identifier: argument.type
663+
count: 1
664+
path: src/symfony/src/Security/Authentication/WebauthnAuthenticator.php
665+
666+
-
667+
message: '#^Parameter \#9 \$extensions of class Webauthn\\Bundle\\Security\\Authentication\\Token\\WebauthnToken constructor expects Webauthn\\AuthenticationExtensions\\AuthenticationExtensions\|null, mixed given\.$#'
668+
identifier: argument.type
669+
count: 1
670+
path: src/symfony/src/Security/Authentication/WebauthnAuthenticator.php
671+
672+
-
673+
message: '#^Class Webauthn\\Bundle\\Security\\Authentication\\WebauthnBadge has an uninitialized property \$authenticatorResponse\. Give it default value or assign it in the constructor\.$#'
674+
identifier: property.uninitialized
675+
count: 1
676+
path: src/symfony/src/Security/Authentication/WebauthnBadge.php
677+
678+
-
679+
message: '#^Class Webauthn\\Bundle\\Security\\Authentication\\WebauthnBadge has an uninitialized property \$publicKeyCredentialOptions\. Give it default value or assign it in the constructor\.$#'
680+
identifier: property.uninitialized
681+
count: 1
682+
path: src/symfony/src/Security/Authentication/WebauthnBadge.php
683+
684+
-
685+
message: '#^Class Webauthn\\Bundle\\Security\\Authentication\\WebauthnBadge has an uninitialized property \$publicKeyCredentialSource\. Give it default value or assign it in the constructor\.$#'
686+
identifier: property.uninitialized
687+
count: 1
688+
path: src/symfony/src/Security/Authentication/WebauthnBadge.php
689+
690+
-
691+
message: '#^Class Webauthn\\Bundle\\Security\\Authentication\\WebauthnBadge has an uninitialized property \$publicKeyCredentialUserEntity\. Give it default value or assign it in the constructor\.$#'
692+
identifier: property.uninitialized
693+
count: 1
694+
path: src/symfony/src/Security/Authentication/WebauthnBadge.php
695+
696+
-
697+
message: '#^Class Webauthn\\Bundle\\Security\\Authentication\\WebauthnBadge has an uninitialized property \$user\. Give it default value or assign it in the constructor\.$#'
698+
identifier: property.uninitialized
699+
count: 1
700+
path: src/symfony/src/Security/Authentication/WebauthnBadge.php
701+
702+
-
703+
message: '#^Method Webauthn\\Bundle\\Security\\Authentication\\WebauthnBadge\:\:__construct\(\) has parameter \$attributes with no value type specified in iterable type array\.$#'
704+
identifier: missingType.iterableValue
705+
count: 1
706+
path: src/symfony/src/Security/Authentication/WebauthnBadge.php
707+
708+
-
709+
message: '#^Property Webauthn\\Bundle\\Security\\Authentication\\WebauthnBadge\:\:\$user \(Symfony\\Component\\Security\\Core\\User\\UserInterface\) does not accept mixed\.$#'
710+
identifier: assign.propertyType
711+
count: 1
712+
path: src/symfony/src/Security/Authentication/WebauthnBadge.php
713+
714+
-
715+
message: '#^Method Webauthn\\Bundle\\Security\\Authentication\\WebauthnBadgeListener\:\:__construct\(\) has parameter \$userProvider with generic interface Symfony\\Component\\Security\\Core\\User\\UserProviderInterface but does not specify its types\: TUser$#'
716+
identifier: missingType.generics
717+
count: 1
718+
path: src/symfony/src/Security/Authentication/WebauthnBadgeListener.php
719+
720+
-
721+
message: '#^Webauthn\\Bundle\\Security\\Authentication\\WebauthnPassport\:\:__construct\(\) does not call parent constructor from Symfony\\Component\\Security\\Http\\Authenticator\\Passport\\Passport\.$#'
722+
identifier: constructor.missingParentCall
723+
count: 1
724+
path: src/symfony/src/Security/Authentication/WebauthnPassport.php
725+
564726
-
565727
message: '#^Method Webauthn\\Bundle\\Security\\Http\\Authenticator\\WebauthnAuthenticator\:\:__construct\(\) has parameter \$userProvider with generic interface Symfony\\Component\\Security\\Core\\User\\UserProviderInterface but does not specify its types\: TUser$#'
566728
identifier: missingType.generics
@@ -1341,12 +1503,6 @@ parameters:
13411503
count: 3
13421504
path: src/webauthn/src/AuthenticationExtensions/AuthenticationExtensions.php
13431505

1344-
-
1345-
message: '#^Cannot unset @readonly Webauthn\\AuthenticationExtensions\\AuthenticationExtensions\:\:\$extensions property\.$#'
1346-
identifier: unset.readOnlyPropertyByPhpDoc
1347-
count: 1
1348-
path: src/webauthn/src/AuthenticationExtensions/AuthenticationExtensions.php
1349-
13501506
-
13511507
message: '#^Class Webauthn\\AuthenticationExtensions\\AuthenticationExtensions implements generic interface ArrayAccess but does not specify its types\: TKey, TValue$#'
13521508
identifier: missingType.generics

rector.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Rector\Config\RectorConfig;
66
use Rector\DeadCode\Rector\ClassMethod\RemoveUnusedPrivateMethodParameterRector;
77
use Rector\Doctrine\Set\DoctrineSetList;
8+
use Rector\Php84\Rector\Param\ExplicitNullableParamTypeRector;
89
use Rector\PHPUnit\CodeQuality\Rector\Class_\PreferPHPUnitThisCallRector;
910
use Rector\PHPUnit\Set\PHPUnitSetList;
1011
use Rector\Set\ValueObject\SetList;
@@ -34,6 +35,7 @@
3435
],
3536
PreferPHPUnitThisCallRector::class,
3637
]);
38+
$config->rule(ExplicitNullableParamTypeRector::class);
3739
$config->phpVersion(PhpVersion::PHP_82);
3840
$config::configure()->withComposerBased(twig: true, doctrine: true, phpunit: true);
3941
$config::configure()->withPhpSets();
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
name: Close Pull Request
2+
3+
on:
4+
pull_request_target:
5+
types: [opened]
6+
7+
jobs:
8+
run:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: superbrothers/close-pull-request@v3
12+
with:
13+
comment: |
14+
Thanks for your Pull Request! We love contributions.
15+
16+
However, you should instead open your PR on the main repository:
17+
https://github.com/web-auth/webauthn-framework
18+
19+
This repository is what we call a "subtree split": a read-only subset of that main repository.
20+
We're looking forward to your PR there!
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
name: Close Pull Request
2+
3+
on:
4+
pull_request_target:
5+
types: [opened]
6+
7+
jobs:
8+
run:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: superbrothers/close-pull-request@v3
12+
with:
13+
comment: |
14+
Thanks for your Pull Request! We love contributions.
15+
16+
However, you should instead open your PR on the main repository:
17+
https://github.com/web-auth/webauthn-framework
18+
19+
This repository is what we call a "subtree split": a read-only subset of that main repository.
20+
We're looking forward to your PR there!

src/symfony/src/Repository/DoctrineCredentialSourceRepository.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414
/**
1515
* @template T of PublicKeyCredentialSource
1616
* @template-extends ServiceEntityRepository<T>
17-
*
18-
* @deprecated since 5.2.0, to be removed in 6.0.0. Please create your own doctrine-based repository.
1917
*/
2018
class DoctrineCredentialSourceRepository extends ServiceEntityRepository implements PublicKeyCredentialSourceRepositoryInterface, CanSaveCredentialSource
2119
{

src/symfony/src/Resources/config/doctrine-mapping/PublicKeyCredentialSource.orm.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping https://raw.github.com/doctrine/doctrine2/master/doctrine-mapping.xsd"
66
>
77
<mapped-superclass name="Webauthn\PublicKeyCredentialSource">
8-
<field name="publicKeyCredentialId" type="base64"/>
8+
<field name="publicKeyCredentialId" type="base64" unique="true" length="250"/>
99
<field name="type"/>
1010
<field name="transports" type="json"/>
1111
<field name="attestationType"/>

src/symfony/src/Resources/config/security.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Webauthn\Bundle\DependencyInjection\Factory\Security\WebauthnFactory;
99
use Webauthn\Bundle\Repository\PublicKeyCredentialSourceRepositoryInterface;
1010
use Webauthn\Bundle\Repository\PublicKeyCredentialUserEntityRepositoryInterface;
11+
use Webauthn\Bundle\Security\Authentication\WebauthnBadgeListener;
1112
use Webauthn\Bundle\Security\Authorization\Voter\IsUserPresentVoter;
1213
use Webauthn\Bundle\Security\Authorization\Voter\IsUserVerifiedVoter;
1314
use Webauthn\Bundle\Security\Guesser\CurrentUserEntityGuesser;
@@ -51,9 +52,7 @@
5152
service(PublicKeyCredentialUserEntityRepositoryInterface::class),
5253
service(SerializerInterface::class),
5354
abstract_arg('Authenticator Assertion Response Validator'),
54-
abstract_arg(
55-
'Authenticator Attestation Response Validator'
56-
), //service(AuthenticatorAttestationResponseValidator::class)
55+
abstract_arg('Authenticator Attestation Response Validator'),
5756
]);
5857
$service
5958
->set(WebauthnFactory::FIREWALL_CONFIG_DEFINITION_ID, WebauthnFirewallConfig::class)
@@ -62,4 +61,5 @@
6261

6362
$service->set(CurrentUserEntityGuesser::class);
6463
$service->set(RequestBodyUserEntityGuesser::class);
64+
$service->set(WebauthnBadgeListener::class);
6565
};
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Webauthn\Bundle\Security\Authentication;
6+
7+
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
8+
use Symfony\Component\Security\Http\Authenticator\AbstractLoginFormAuthenticator;
9+
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
10+
use Webauthn\AuthenticatorAssertionResponse;
11+
use Webauthn\Bundle\Security\Authentication\Token\WebauthnToken;
12+
use function assert;
13+
14+
abstract class WebauthnAuthenticator extends AbstractLoginFormAuthenticator
15+
{
16+
public function createToken(Passport $passport, string $firewallName): TokenInterface
17+
{
18+
assert($passport instanceof WebauthnPassport, 'Invalid passport');
19+
$webauthnBadge = $passport->getBadge(WebauthnBadge::class);
20+
assert($webauthnBadge instanceof WebauthnBadge, 'Invalid badge');
21+
if ($webauthnBadge->getAuthenticatorResponse() instanceof AuthenticatorAssertionResponse) {
22+
$authData = $webauthnBadge->getAuthenticatorResponse()
23+
->authenticatorData;
24+
} else {
25+
$authData = $webauthnBadge->getAuthenticatorResponse()
26+
->attestationObject
27+
->authData;
28+
}
29+
30+
$token = new WebauthnToken(
31+
$webauthnBadge->getPublicKeyCredentialUserEntity(),
32+
$webauthnBadge->getPublicKeyCredentialOptions(),
33+
$webauthnBadge->getPublicKeyCredentialSource()
34+
->getPublicKeyCredentialDescriptor(),
35+
$authData->isUserPresent(),
36+
$authData->isUserVerified(),
37+
$authData->getReservedForFutureUse1(),
38+
$authData->getReservedForFutureUse2(),
39+
$authData->signCount,
40+
$authData->extensions,
41+
$firewallName,
42+
$webauthnBadge->getUser()
43+
->getRoles(),
44+
$authData->isBackupEligible(),
45+
$authData->isBackedUp(),
46+
);
47+
$token->setUser($webauthnBadge->getUser());
48+
49+
return $token;
50+
}
51+
}

0 commit comments

Comments
 (0)