diff --git a/.env b/.env index ef0afda..efd6c63 100644 --- a/.env +++ b/.env @@ -2,6 +2,7 @@ APP_ENV=prod DEFAULT_LOCALE=en APP_SECRET=CHANGEME TZ=America/New_York +LOGIN_JSON_AES_KEY= ###> symfony/lock ### # Choose one of the stores below # postgresql+advisory://db_user:db_password@localhost/db_name diff --git a/README.md b/README.md index 7a4fe07..858d6e7 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,21 @@ This is a web panel to allow roleplay server to have an common interface for all php bin/console cache:clear ``` +## Login with json token + + +you need to encode a json string like this : +```php +openssl_encrypt('{"email":"test@test.fr"}', 'aes-256-cbc', 'LOGIN_JSON_AES_KEY', 0) +``` +and then use the token with url : + +/login/json?token=YOUR_ENCRYPTED_TOKEN_HERE + +If the email exist on user list, the user is connected, if not, and error page is displayed + +You need to setup the decryption key by env : LOGIN_JSON_AES_KEY + ## Scalability Vision is ready to be used in scaled architecture : diff --git a/config/packages/security.yaml b/config/packages/security.yaml index 939219f..3bc5f2a 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -20,7 +20,9 @@ security: lazy: true provider: app_user_provider switch_user: { role: ROLE_ADMIN, parameter: _want_to_be_this_user } - custom_authenticator: App\Security\FormAuthenticator + custom_authenticator: + - App\Security\FormAuthenticator + - App\Security\JsonAesAuthenticator user_checker: App\Security\UserChecker login_throttling: max_attempts: 3 diff --git a/src/Controller/SecurityController.php b/src/Controller/SecurityController.php index 310c9ad..8c4f640 100644 --- a/src/Controller/SecurityController.php +++ b/src/Controller/SecurityController.php @@ -138,4 +138,15 @@ class SecurityController extends AbstractController { throw new \LogicException('Something goes wrong if you see this'); } + + /** + * @Route("/login/json", name="app_login_json") + */ + public function loginJson() + { + + return $this->render( + 'security/json.html.twig' + ); + } } diff --git a/src/Security/JsonAesAuthenticator.php b/src/Security/JsonAesAuthenticator.php new file mode 100644 index 0000000..7b6c737 --- /dev/null +++ b/src/Security/JsonAesAuthenticator.php @@ -0,0 +1,71 @@ +urlGenerator = $urlGenerator; + $this->userRepository = $userRepository; + } + + + public function supports(Request $request): ?bool + { + return ($request->attributes->get('_route') == 'app_login_json') + && $request->query->has('token') + && null != $_ENV['LOGIN_JSON_AES_KEY'] + && !empty($_ENV['LOGIN_JSON_AES_KEY']); + } + + public function authenticate(Request $request): Passport + { + + $apiToken = $request->query->get('token'); + if (null === $apiToken) { + throw new AccessDeniedHttpException('No API token provided'); + } + + $tokenDecoded = openssl_decrypt($apiToken, 'aes-256-cbc', $_ENV['LOGIN_JSON_AES_KEY'], 0); + $tokenInfos = json_decode($tokenDecoded); + + return new SelfValidatingPassport(new UserBadge($tokenInfos->email, function (string $userIdentifier) { + return $this->userRepository->findOneBy(['email' => $userIdentifier]); + })); + } + + public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response + { + + if ($targetPath = $this->getTargetPath($request->getSession(), $firewallName)) { + return new RedirectResponse($targetPath); + } + + return new RedirectResponse($this->urlGenerator->generate('home')); + } + + public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response + { + return new RedirectResponse($this->urlGenerator->generate('app_login_json')); + } +} diff --git a/templates/security/json.html.twig b/templates/security/json.html.twig new file mode 100644 index 0000000..26c542f --- /dev/null +++ b/templates/security/json.html.twig @@ -0,0 +1,29 @@ +{% extends 'base.html.twig' %} + +{% block title %}{% trans %}title_login{% endtrans %}{% endblock %} + +{% block body %} + + +
+
+
+
+
+
+ +

{% trans %}title_login{% endtrans %}

+ +

{% trans %}text_login_json_fail{% endtrans %}

+ +

{% trans %}no_account{% endtrans %} ? {% trans %}button_register{% endtrans %}

+ + +
+
+
+
+
+
+ +{% endblock %} diff --git a/translations/messages+intl-icu.en.yaml b/translations/messages+intl-icu.en.yaml index 236cc68..68b5760 100644 --- a/translations/messages+intl-icu.en.yaml +++ b/translations/messages+intl-icu.en.yaml @@ -619,6 +619,7 @@ subtitle_administration_watchdog: View entities modifications subtitle_administration: The BOSS subtitle_home: Homepage subtitle_management: Administration of your group +text_login_json_fail: Automatic login failed, contact your administrator text_reset_password_explanation: If an account is linked to this address, you will receive an email with a reset link title_accessorySentence: Accessory penalty title_actions: Actions diff --git a/translations/messages+intl-icu.fr.yaml b/translations/messages+intl-icu.fr.yaml index 3a4d006..9245fcf 100644 --- a/translations/messages+intl-icu.fr.yaml +++ b/translations/messages+intl-icu.fr.yaml @@ -618,6 +618,7 @@ subtitle_administration_watchdog: Voir les modifications des entités subtitle_administration: Les BOSS subtitle_home: Accueil subtitle_management: Gestion de votre groupe +text_login_json_fail: La connexion automatique à échouée, merci de contacter l'équipe technique text_reset_password_explanation: Si un compte est lié à cette adresse, vous allez recevoir un email avec un lien de réinitialisation title_accessorySentence: Peine Accessoire title_actions: Actions diff --git a/visionversion.json b/visionversion.json index 42be9b0..1720cd8 100644 --- a/visionversion.json +++ b/visionversion.json @@ -1,3 +1,3 @@ { - "version": "0.2.18" + "version": "0.2.19" }