Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added custom login authenticator, + api connet me endpoint. #28

Merged
merged 3 commits into from
Mar 4, 2024
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
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
Loading