Skip to content

Commit

Permalink
Added custom login authenticator, + api connet me endpoint. (#28)
Browse files Browse the repository at this point in the history
* Added custom login authenticator, + api connet me endpoint.

* Fix RouterConfigurationSnapShotTest.

* Fix security.yaml.
  • Loading branch information
zerai authored Mar 4, 2024
1 parent c3a23ce commit 1782d36
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 14 deletions.
39 changes: 39 additions & 0 deletions _iam/src/AdapterForApi/Auth/ConnectMeController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php declare(strict_types=1);

/*
* This file is part of the medicalmundi/marketplace-accounts
*
* @copyright (c) 2023 MedicalMundi
*
* This software consists of voluntary contributions made by many individuals
* {@link https://github.com/medicalmundi/marketplace-accounts/graphs/contributors developer} and is licensed under the MIT license.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
* @license https://github.com/MedicalMundi/marketplace-accounts/blob/main/LICENSE MIT
*/

namespace IdentityAccess\AdapterForApi\Auth;

use App\Entity\User;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;

#[Route('/api/v1/auth')]
class ConnectMeController extends AbstractController
{
#[Route('/connect/me', name: 'api_auth_connect_me', methods: 'GET')]
#[isGranted('ROLE_USER')]
public function index(): Response
{
/** @var User $user */
$user = $this->getUser();

return $this->json([
'id' => $user->getId(),
'email' => $user->getEmail(),
]);
}
}
19 changes: 5 additions & 14 deletions config/packages/security.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,23 @@ security:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
api_token:
pattern: ^/api/token$
security: false
api:
pattern: ^/api
security: true
stateless: true
oauth2: true
main:
# login_throttling:
# max_attempts: 3
# interval: '5 minutes'
login_throttling:
max_attempts: 6
interval: '5 minutes'
lazy: true
provider: app_user_provider
form_login:
login_path: app_login
check_path: app_login
enable_csrf: true
default_target_path: app_index
use_referer: true
custom_authenticators:
- App\Security\Authenticator\OeModulesLoginFormAuthenticator
logout:
path: app_logout
target: app_index

login_throttling: true

# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#the-firewall

Expand Down
7 changes: 7 additions & 0 deletions config/routes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,10 @@ iam_admin_oauth_client_controllers:
path: ../_iam/src/AdapterForWeb/Administration/OauthClient/
namespace: IdentityAccess\AdapterForWeb\Administration\OauthClient
type: attribute


api_auth_controllers:
resource:
path: ../_iam/src/AdapterForApi/Auth/
namespace: IdentityAccess\AdapterForApi\Auth
type: attribute
88 changes: 88 additions & 0 deletions src/Security/Authenticator/OeModulesLoginFormAuthenticator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php declare(strict_types=1);

/*
* This file is part of the medicalmundi/marketplace-accounts
*
* @copyright (c) 2023 MedicalMundi
*
* This software consists of voluntary contributions made by many individuals
* {@link https://github.com/medicalmundi/marketplace-accounts/graphs/contributors developer} and is licensed under the MIT license.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
* @license https://github.com/MedicalMundi/marketplace-accounts/blob/main/LICENSE MIT
*/

namespace App\Security\Authenticator;

use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\User\PasswordUpgraderInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Http\Authenticator\AbstractLoginFormAuthenticator;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\PasswordUpgradeBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\RememberMeBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\ParameterBagUtils;
use Symfony\Component\Security\Http\SecurityRequestAttributes;
use Symfony\Component\Security\Http\Util\TargetPathTrait;

class OeModulesLoginFormAuthenticator extends AbstractLoginFormAuthenticator
{
use TargetPathTrait;

public function __construct(
private readonly UserProviderInterface $userProvider,
private readonly UrlGeneratorInterface $urlGenerator
) {
}

protected function getLoginUrl(Request $request): string
{
return $this->urlGenerator->generate('app_login');
}

public function authenticate(Request $request): Passport
{
$credentials = $this->getCredentials($request);

$userBadge = new UserBadge((string) $credentials['username'], $this->userProvider->loadUserByIdentifier(...));
$passport = new Passport($userBadge, new PasswordCredentials((string) $credentials['password']), [new RememberMeBadge()]);

if ($this->userProvider instanceof PasswordUpgraderInterface) {
$passport->addBadge(new PasswordUpgradeBadge((string) $credentials['password'], $this->userProvider));
}

return $passport;
}

public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
{
if (null !== ($targetPath = $this->getTargetPath($request->getSession(), $firewallName))) {
return new RedirectResponse($targetPath);
}

return new RedirectResponse($this->urlGenerator->generate('app_index'));
}

private function getCredentials(Request $request): array
{
$credentials = [];
//TODO
//$credentials['csrf_token'] = ParameterBagUtils::getRequestParameterValue($request, $this->options['csrf_parameter']);

$credentials['username'] = (string) $request->request->get('_username', '');
$credentials['password'] = (string) $request->request->get('_password', '');

$credentials['username'] = trim($credentials['username']);

$request->getSession()->set(SecurityRequestAttributes::LAST_USERNAME, $credentials['username']);

return $credentials;
}
}
10 changes: 10 additions & 0 deletions tests/Integration/Regression/Fixture/expected_route_map.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
{
"api_auth_connect_me": {
"path": "\/api\/v1\/auth\/connect\/me",
"requirements": [],
"defaults": {
"_controller": "IdentityAccess\\AdapterForApi\\Auth\\ConnectMeController::index"
},
"methods": [
"GET"
]
},
"app_api_security_index": {
"path": "\/api\/security\/test",
"requirements": [],
Expand Down

0 comments on commit 1782d36

Please sign in to comment.