Skip to content

Commit 3062ee4

Browse files
RAB-1149: Add manager_authentication support (#2)
* RAB-1149: Add support of new symfony authentication_manager * RAB-1149: Fix depreciation Co-authored-by: Grégoire Houssard <ghoussard@protonmail.com>
1 parent 79b0dd8 commit 3062ee4

5 files changed

Lines changed: 151 additions & 3 deletions

File tree

DependencyInjection/FOSOAuthServerExtension.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ public function load(array $configs, ContainerBuilder $container)
104104
/**
105105
* {@inheritdoc}
106106
*/
107-
public function getAlias()
107+
public function getAlias(): string
108108
{
109109
return 'fos_oauth_server';
110110
}

DependencyInjection/Security/Factory/OAuthFactory.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
namespace FOS\OAuthServerBundle\DependencyInjection\Security\Factory;
1515

16+
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\AuthenticatorFactoryInterface;
1617
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface;
1718
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
1819
use Symfony\Component\DependencyInjection\ChildDefinition;
@@ -24,8 +25,21 @@
2425
*
2526
* @author Arnaud Le Blanc <arnaud.lb@gmail.com>
2627
*/
27-
class OAuthFactory implements SecurityFactoryInterface
28+
class OAuthFactory implements AuthenticatorFactoryInterface, SecurityFactoryInterface
2829
{
30+
public function createAuthenticator(ContainerBuilder $container, string $id, array $config, string $userProviderId)
31+
{
32+
$providerId = 'fos_oauth_server.security.authentication.authenticator.'.$id;
33+
$container
34+
->setDefinition($providerId, new ChildDefinition('fos_oauth_server.security.authentication.authenticator'))
35+
->replaceArgument(0, new Reference('fos_oauth_server.server'))
36+
->replaceArgument(1, new Reference('security.user_checker.'.$id))
37+
->replaceArgument(2, new Reference($userProviderId))
38+
;
39+
40+
return $providerId;
41+
}
42+
2943
/**
3044
* {@inheritdoc}
3145
*/

Resources/config/security.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@
1717
<argument type="service" id="security.user_checker" />
1818
</service>
1919

20+
<service id="fos_oauth_server.security.authentication.authenticator" class="FOS\OAuthServerBundle\Security\Authentication\Authenticator\OAuthAuthenticator" public="false">
21+
<argument type="service" id="fos_oauth_server.server" />
22+
<argument type="service" id="security.user_checker" />
23+
<argument /> <!-- user provider -->
24+
</service>
25+
2026
<service id="fos_oauth_server.security.authentication.listener" class="%fos_oauth_server.security.authentication.listener.class%" public="false">
2127
<argument type="service" id="security.token_storage"/>
2228
<argument type="service" id="security.authentication.manager" />
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the FOSOAuthServerBundle package.
7+
*
8+
* (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
9+
*
10+
* For the full copyright and license information, please view the LICENSE
11+
* file that was distributed with this source code.
12+
*/
13+
14+
namespace FOS\OAuthServerBundle\Security\Authentication\Authenticator;
15+
16+
use FOS\OAuthServerBundle\Security\Authentication\Token\OAuthToken;
17+
use OAuth2\OAuth2;
18+
use OAuth2\OAuth2AuthenticateException;
19+
use OAuth2\OAuth2ServerException;
20+
use Symfony\Component\HttpFoundation\Request;
21+
use Symfony\Component\HttpFoundation\Response;
22+
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
23+
use Symfony\Component\Security\Core\Exception\AuthenticationException;
24+
use Symfony\Component\Security\Core\User\UserInterface;
25+
use Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface;
26+
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
27+
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
28+
use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface;
29+
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
30+
31+
class OAuthAuthenticator implements AuthenticatorInterface
32+
{
33+
public function __construct(
34+
private OAuth2 $oauthService,
35+
) {
36+
}
37+
38+
/**
39+
* {@inheritdoc}
40+
*/
41+
public function authenticate(Request $request): Passport
42+
{
43+
$tokenString = $this->oauthService->getBearerToken($request, true);
44+
45+
try {
46+
$accessToken = $this->oauthService->verifyAccessToken($tokenString);
47+
} catch (OAuth2AuthenticateException $e) {
48+
throw new AuthenticationException('OAuth2 authentication failed', 0, $e);
49+
}
50+
51+
$scope = $accessToken->getScope();
52+
$user = $accessToken->getUser();
53+
$username = $user instanceof UserInterface ? $user->getUserIdentifier() : '';
54+
55+
$userBadge = new UserBadge($username);
56+
57+
return new SelfValidatingPassport($userBadge);
58+
}
59+
60+
/**
61+
* @TODO should be removed when Symfony > 6.0
62+
* {@inheritdoc}
63+
*/
64+
public function createAuthenticatedToken(PassportInterface $passport, string $firewallName): TokenInterface
65+
{
66+
if (!$passport instanceof Passport) {
67+
throw new \RuntimeException(sprintf('Cannot create a OAuth2 authenticated token. $passport should be a %s', Passport::class));
68+
}
69+
70+
$token = $this->createToken($passport, $firewallName);
71+
$token->setAuthenticated(true);
72+
73+
return $token;
74+
}
75+
76+
public function createToken(Passport $passport, string $firewallName): TokenInterface
77+
{
78+
$roles = $passport->getUser()->getRoles();
79+
80+
$token = new OAuthToken($roles);
81+
$token->setUser($passport->getUser());
82+
83+
/** @TODO should be removed when Symfony > 6.0 */
84+
if (method_exists(AuthenticatorInterface::class, 'createAuthenticatedToken') && !method_exists(AuthenticatorInterface::class, 'createToken')) {
85+
$token->setAuthenticated(true, false);
86+
}
87+
88+
return $token;
89+
}
90+
91+
/**
92+
* {@inheritdoc}
93+
*/
94+
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
95+
{
96+
return null;
97+
}
98+
99+
/**
100+
* {@inheritdoc}
101+
*/
102+
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
103+
{
104+
if ($exception instanceof OAuth2ServerException) {
105+
return new Response($exception->getMessage(), (int) $exception->getHttpCode(), $exception->getResponseHeaders());
106+
}
107+
108+
$responseException = new OAuth2AuthenticateException(
109+
(string) Response::HTTP_UNAUTHORIZED,
110+
OAuth2::TOKEN_TYPE_BEARER,
111+
$this->oauthService->getVariable(OAuth2::CONFIG_WWW_REALM),
112+
'access_denied',
113+
$exception->getMessage()
114+
);
115+
116+
return $responseException->getHttpResponse();
117+
}
118+
119+
/**
120+
* {@inheritdoc}
121+
*/
122+
public function supports(Request $request): ?bool
123+
{
124+
$tokenString = $this->oauthService->getBearerToken($request);
125+
126+
return is_string($tokenString) && !empty($tokenString);
127+
}
128+
}

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
}
2121
],
2222
"require": {
23-
"php": "^7.2 || ^8.0",
23+
"php": "^8.0",
2424
"friendsofsymfony/oauth2-php": "~1.1",
2525
"symfony/dependency-injection": "^4.4 || ^5.1",
2626
"symfony/framework-bundle": "^4.4 || ^5.1",

0 commit comments

Comments
 (0)