From c2fe357601cbd307a23d42a42510d3c6f0ad5b6b Mon Sep 17 00:00:00 2001 From: mploierMacBook Date: Thu, 14 Mar 2024 10:33:57 +0100 Subject: [PATCH 01/12] feat: Add LDAP basis config --- backend/.env.example | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/backend/.env.example b/backend/.env.example index 58a6e15..9d3546e 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -46,3 +46,8 @@ MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0 ###> symfony/mailer ### # MAILER_DSN=null://null ###< symfony/mailer ### + +###> LDAP ### +LDAP_PORT=YOUR_PORT +LDAP_URL=ldaps://YOUR_ADDRESS:${LDAP_PORT} +LDAP_BASE=YOUR_BASE From b4e3dee8aa54e43c7124e04196fa7429b630d633 Mon Sep 17 00:00:00 2001 From: mploierMacBook Date: Mon, 18 Mar 2024 08:20:41 +0100 Subject: [PATCH 02/12] feat: authenticate with URL localhost/ldaps and Parameters user(usr) and password(pwd) against the LDAP-Server --- backend/src/Controller/LoginController.php | 49 ++++++++++++++++++++++ backend/templates/ldap/index.html.twig | 8 ++++ 2 files changed, 57 insertions(+) create mode 100644 backend/src/Controller/LoginController.php create mode 100644 backend/templates/ldap/index.html.twig diff --git a/backend/src/Controller/LoginController.php b/backend/src/Controller/LoginController.php new file mode 100644 index 0000000..6d83ff7 --- /dev/null +++ b/backend/src/Controller/LoginController.php @@ -0,0 +1,49 @@ +get("usr"); + $pwd = $request->get("pwd"); + try { + $success = $this->authenticateUser($user, $pwd); + } catch (LdapException | Exception $e) { + $success = false; + } + $success = ($success) ? "true" : "false"; + + + return $this->render('ldap/index.html.twig', [ + "info"=> [$success] + ]); + } + + private function authenticateUser($user, $password): bool + { + $ds = ldap_connect($_ENV["LDAP_URL"]) or throw new LdapException("Could not connect to LDAP server."); + if ($ds) { + $r = ldap_bind($ds) or die ("Error trying to bind: " . ldap_error($ds)); + + // Search the users dn as anonymous + $sr = ldap_search($ds, $_ENV["LDAP_BASE"], "cn=" . $user, array("dn")) or throw new LdapException ("Error in search query: " . ldap_error($ds)); + $res = ldap_get_entries($ds, $sr); + $userDN = $res[0]['dn']; + $r = ldap_bind($ds, $userDN, $password) or throw new LdapException("Error trying to bind: " . ldap_error($ds)); + } + return true; + } +} diff --git a/backend/templates/ldap/index.html.twig b/backend/templates/ldap/index.html.twig new file mode 100644 index 0000000..8dbd72f --- /dev/null +++ b/backend/templates/ldap/index.html.twig @@ -0,0 +1,8 @@ +{% block body %} + + {% for item in info %} +

{{ item }}

+ {% endfor %} + + +{% endblock %} \ No newline at end of file From 061c6ff65e978dfccc0f11c24d86b3ab8e6ea803 Mon Sep 17 00:00:00 2001 From: mploierMacBook Date: Mon, 18 Mar 2024 09:27:10 +0100 Subject: [PATCH 03/12] fixed: added JsonReturn for login-success. URL localhost/ldaps returns now a JSON --- backend/src/Controller/LoginController.php | 12 +++--- backend/src/Entity/JsonReturn.php | 43 ++++++++++++++++++++++ 2 files changed, 49 insertions(+), 6 deletions(-) create mode 100644 backend/src/Entity/JsonReturn.php diff --git a/backend/src/Controller/LoginController.php b/backend/src/Controller/LoginController.php index 6d83ff7..be94731 100644 --- a/backend/src/Controller/LoginController.php +++ b/backend/src/Controller/LoginController.php @@ -2,14 +2,16 @@ namespace App\Controller; +use App\Entity\JsonReturn; use Exception; use Psr\Log\LogLevel; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Log\Logger; -use Symfony\Component\Ldap\Exception\LdapException; use Symfony\Component\Routing\Attribute\Route; +use Symfony\Component\Validator\Constraints\Json; use function Symfony\Component\DependencyInjection\Loader\Configurator\env; class LoginController extends AbstractController @@ -21,15 +23,13 @@ public function index(Request $request): Response $pwd = $request->get("pwd"); try { $success = $this->authenticateUser($user, $pwd); - } catch (LdapException | Exception $e) { + } catch (LdapException|Exception $e) { $success = false; } - $success = ($success) ? "true" : "false"; + $return = new JsonReturn($success); - return $this->render('ldap/index.html.twig', [ - "info"=> [$success] - ]); + return new JsonResponse(json_encode($return), 200, [], true); } private function authenticateUser($user, $password): bool diff --git a/backend/src/Entity/JsonReturn.php b/backend/src/Entity/JsonReturn.php new file mode 100644 index 0000000..39c93ab --- /dev/null +++ b/backend/src/Entity/JsonReturn.php @@ -0,0 +1,43 @@ +id = uniqid(); + $this->validation = $validation; + } + + + public function getId(): string + { + return $this->id; + } + + public function setId(string $id): void + { + $this->id = $id; + } + + public function isValidation(): bool + { + return $this->validation; + } + + public function setValidation(bool $validation): void + { + $this->validation = $validation; + } + + +} \ No newline at end of file From 103673d5d1968d2bad91377f1eb2c732473ebde8 Mon Sep 17 00:00:00 2001 From: mploierMacBook Date: Mon, 18 Mar 2024 09:27:10 +0100 Subject: [PATCH 04/12] fix: added JsonReturn for login-success. URL localhost/ldaps returns now a JSON --- backend/src/Controller/LoginController.php | 12 +++--- backend/src/Entity/JsonReturn.php | 43 ++++++++++++++++++++++ 2 files changed, 49 insertions(+), 6 deletions(-) create mode 100644 backend/src/Entity/JsonReturn.php diff --git a/backend/src/Controller/LoginController.php b/backend/src/Controller/LoginController.php index 6d83ff7..be94731 100644 --- a/backend/src/Controller/LoginController.php +++ b/backend/src/Controller/LoginController.php @@ -2,14 +2,16 @@ namespace App\Controller; +use App\Entity\JsonReturn; use Exception; use Psr\Log\LogLevel; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Log\Logger; -use Symfony\Component\Ldap\Exception\LdapException; use Symfony\Component\Routing\Attribute\Route; +use Symfony\Component\Validator\Constraints\Json; use function Symfony\Component\DependencyInjection\Loader\Configurator\env; class LoginController extends AbstractController @@ -21,15 +23,13 @@ public function index(Request $request): Response $pwd = $request->get("pwd"); try { $success = $this->authenticateUser($user, $pwd); - } catch (LdapException | Exception $e) { + } catch (LdapException|Exception $e) { $success = false; } - $success = ($success) ? "true" : "false"; + $return = new JsonReturn($success); - return $this->render('ldap/index.html.twig', [ - "info"=> [$success] - ]); + return new JsonResponse(json_encode($return), 200, [], true); } private function authenticateUser($user, $password): bool diff --git a/backend/src/Entity/JsonReturn.php b/backend/src/Entity/JsonReturn.php new file mode 100644 index 0000000..39c93ab --- /dev/null +++ b/backend/src/Entity/JsonReturn.php @@ -0,0 +1,43 @@ +id = uniqid(); + $this->validation = $validation; + } + + + public function getId(): string + { + return $this->id; + } + + public function setId(string $id): void + { + $this->id = $id; + } + + public function isValidation(): bool + { + return $this->validation; + } + + public function setValidation(bool $validation): void + { + $this->validation = $validation; + } + + +} \ No newline at end of file From ad7841dd50bc06ed8fc1caadca5d9414a0024968 Mon Sep 17 00:00:00 2001 From: mploierMacBook Date: Thu, 21 Mar 2024 15:01:13 +0100 Subject: [PATCH 05/12] fixed: renamed JsonReturn.php to AuthToken.php --- backend/src/Entity/AuthToken.php | 43 +++++++++++++++++++++++++++++++ backend/src/Entity/JsonReturn.php | 43 ------------------------------- 2 files changed, 43 insertions(+), 43 deletions(-) create mode 100644 backend/src/Entity/AuthToken.php delete mode 100644 backend/src/Entity/JsonReturn.php diff --git a/backend/src/Entity/AuthToken.php b/backend/src/Entity/AuthToken.php new file mode 100644 index 0000000..6d2da99 --- /dev/null +++ b/backend/src/Entity/AuthToken.php @@ -0,0 +1,43 @@ +value = uniqid(); + $this->success = $validation; + } + + + public function getValue(): string + { + return $this->value; + } + + public function setValue(string $value): void + { + $this->value = $value; + } + + public function isSuccess(): bool + { + return $this->success; + } + + public function setSuccess(bool $success): void + { + $this->success = $success; + } + + +} \ No newline at end of file diff --git a/backend/src/Entity/JsonReturn.php b/backend/src/Entity/JsonReturn.php deleted file mode 100644 index 39c93ab..0000000 --- a/backend/src/Entity/JsonReturn.php +++ /dev/null @@ -1,43 +0,0 @@ -id = uniqid(); - $this->validation = $validation; - } - - - public function getId(): string - { - return $this->id; - } - - public function setId(string $id): void - { - $this->id = $id; - } - - public function isValidation(): bool - { - return $this->validation; - } - - public function setValidation(bool $validation): void - { - $this->validation = $validation; - } - - -} \ No newline at end of file From 4228a8151b43bee5bedba7ae380e5c393e74c818 Mon Sep 17 00:00:00 2001 From: mploierMacBook Date: Thu, 21 Mar 2024 15:03:01 +0100 Subject: [PATCH 06/12] feat: Created local LDAP-Server, adapt LDAP-request for test environment --- backend/src/Controller/LoginController.php | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/backend/src/Controller/LoginController.php b/backend/src/Controller/LoginController.php index be94731..45adeed 100644 --- a/backend/src/Controller/LoginController.php +++ b/backend/src/Controller/LoginController.php @@ -2,7 +2,7 @@ namespace App\Controller; -use App\Entity\JsonReturn; +use App\Entity\AuthToken; use Exception; use Psr\Log\LogLevel; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; @@ -26,7 +26,7 @@ public function index(Request $request): Response } catch (LdapException|Exception $e) { $success = false; } - $return = new JsonReturn($success); + $return = new AuthToken($success); return new JsonResponse(json_encode($return), 200, [], true); @@ -38,11 +38,21 @@ private function authenticateUser($user, $password): bool if ($ds) { $r = ldap_bind($ds) or die ("Error trying to bind: " . ldap_error($ds)); - // Search the users dn as anonymous - $sr = ldap_search($ds, $_ENV["LDAP_BASE"], "cn=" . $user, array("dn")) or throw new LdapException ("Error in search query: " . ldap_error($ds)); - $res = ldap_get_entries($ds, $sr); - $userDN = $res[0]['dn']; + /** + * LDAP-Request for school + * + * $sr = ldap_search($ds, $_ENV["SCHULE_BASE"], "cn=$user", array("dn")) or throw new LdapException ("Error in search query: " . ldap_error($ds)); + * $res = ldap_get_entries($ds, $sr); + * $userDN = $res[0]['dn']; + */ + + /** + * LDAP-Request for Test-Environment + */ + $userDN="cn=$user,ou=TestUsers," . $_ENV["LDAP_BASE"]; + $r = ldap_bind($ds, $userDN, $password) or throw new LdapException("Error trying to bind: " . ldap_error($ds)); + ldap_close($ds); } return true; } From bb11a2c5c86b42d6d0769948c8ac2ab6cf19a1a4 Mon Sep 17 00:00:00 2001 From: mploierMacBook Date: Thu, 21 Mar 2024 15:43:40 +0100 Subject: [PATCH 07/12] fix: Abstracted authenticateUser($user, $password) function from LoginController.php into AuthService.php --- backend/src/Controller/LoginController.php | 40 ++-------------------- backend/src/Service/AuthService.php | 39 +++++++++++++++++++++ 2 files changed, 42 insertions(+), 37 deletions(-) create mode 100644 backend/src/Service/AuthService.php diff --git a/backend/src/Controller/LoginController.php b/backend/src/Controller/LoginController.php index 45adeed..85875ee 100644 --- a/backend/src/Controller/LoginController.php +++ b/backend/src/Controller/LoginController.php @@ -3,57 +3,23 @@ namespace App\Controller; use App\Entity\AuthToken; -use Exception; -use Psr\Log\LogLevel; +use App\Service\AuthService; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\Log\Logger; use Symfony\Component\Routing\Attribute\Route; -use Symfony\Component\Validator\Constraints\Json; -use function Symfony\Component\DependencyInjection\Loader\Configurator\env; class LoginController extends AbstractController { #[Route('/ldaps', name: 'app_ldap')] - public function index(Request $request): Response + public function index(AuthService $authService, Request $request): Response { $user = $request->get("usr"); $pwd = $request->get("pwd"); - try { - $success = $this->authenticateUser($user, $pwd); - } catch (LdapException|Exception $e) { - $success = false; - } - $return = new AuthToken($success); + $return = new AuthToken($authService->authenticateUser($user, $pwd)); return new JsonResponse(json_encode($return), 200, [], true); } - - private function authenticateUser($user, $password): bool - { - $ds = ldap_connect($_ENV["LDAP_URL"]) or throw new LdapException("Could not connect to LDAP server."); - if ($ds) { - $r = ldap_bind($ds) or die ("Error trying to bind: " . ldap_error($ds)); - - /** - * LDAP-Request for school - * - * $sr = ldap_search($ds, $_ENV["SCHULE_BASE"], "cn=$user", array("dn")) or throw new LdapException ("Error in search query: " . ldap_error($ds)); - * $res = ldap_get_entries($ds, $sr); - * $userDN = $res[0]['dn']; - */ - - /** - * LDAP-Request for Test-Environment - */ - $userDN="cn=$user,ou=TestUsers," . $_ENV["LDAP_BASE"]; - - $r = ldap_bind($ds, $userDN, $password) or throw new LdapException("Error trying to bind: " . ldap_error($ds)); - ldap_close($ds); - } - return true; - } } diff --git a/backend/src/Service/AuthService.php b/backend/src/Service/AuthService.php new file mode 100644 index 0000000..11f2c96 --- /dev/null +++ b/backend/src/Service/AuthService.php @@ -0,0 +1,39 @@ + \ No newline at end of file From 46dd5b30532289f804da997c4ac0bddf17da9805 Mon Sep 17 00:00:00 2001 From: mploierMacBook Date: Thu, 21 Mar 2024 15:48:50 +0100 Subject: [PATCH 08/12] feat: added lexik/jwt-authentication-bundle requirement --- backend/.gitignore | 4 + backend/composer.json | 1 + backend/composer.lock | 393 ++++++++++++++++++++++++++++++++++++- backend/config/bundles.php | 1 + backend/symfony.lock | 12 ++ 5 files changed, 410 insertions(+), 1 deletion(-) diff --git a/backend/.gitignore b/backend/.gitignore index 4daae38..9a3addd 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -23,3 +23,7 @@ /public/assets/ /assets/vendor/ ###< symfony/asset-mapper ### + +###> lexik/jwt-authentication-bundle ### +/config/jwt/*.pem +###< lexik/jwt-authentication-bundle ### diff --git a/backend/composer.json b/backend/composer.json index bb7d0c6..b28f468 100644 --- a/backend/composer.json +++ b/backend/composer.json @@ -11,6 +11,7 @@ "doctrine/doctrine-bundle": "^2.11", "doctrine/doctrine-migrations-bundle": "^3.3", "doctrine/orm": "^3.1", + "lexik/jwt-authentication-bundle": "^2.20", "phpdocumentor/reflection-docblock": "^5.3", "phpstan/phpdoc-parser": "^1.26", "symfony/asset": "7.0.*", diff --git a/backend/composer.lock b/backend/composer.lock index 0c8b3da..131ff4c 100644 --- a/backend/composer.lock +++ b/backend/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "0ea40e77c07ea586d768c874d304b5c5", + "content-hash": "a5e0f1462626ad53ff50aea601f60941", "packages": [ { "name": "composer/semver", @@ -1372,6 +1372,262 @@ ], "time": "2023-10-06T06:47:41+00:00" }, + { + "name": "lcobucci/clock", + "version": "3.2.0", + "source": { + "type": "git", + "url": "https://github.com/lcobucci/clock.git", + "reference": "6f28b826ea01306b07980cb8320ab30b966cd715" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lcobucci/clock/zipball/6f28b826ea01306b07980cb8320ab30b966cd715", + "reference": "6f28b826ea01306b07980cb8320ab30b966cd715", + "shasum": "" + }, + "require": { + "php": "~8.2.0 || ~8.3.0", + "psr/clock": "^1.0" + }, + "provide": { + "psr/clock-implementation": "1.0" + }, + "require-dev": { + "infection/infection": "^0.27", + "lcobucci/coding-standard": "^11.0.0", + "phpstan/extension-installer": "^1.3.1", + "phpstan/phpstan": "^1.10.25", + "phpstan/phpstan-deprecation-rules": "^1.1.3", + "phpstan/phpstan-phpunit": "^1.3.13", + "phpstan/phpstan-strict-rules": "^1.5.1", + "phpunit/phpunit": "^10.2.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Lcobucci\\Clock\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Luís Cobucci", + "email": "lcobucci@gmail.com" + } + ], + "description": "Yet another clock abstraction", + "support": { + "issues": "https://github.com/lcobucci/clock/issues", + "source": "https://github.com/lcobucci/clock/tree/3.2.0" + }, + "funding": [ + { + "url": "https://github.com/lcobucci", + "type": "github" + }, + { + "url": "https://www.patreon.com/lcobucci", + "type": "patreon" + } + ], + "time": "2023-11-17T17:00:27+00:00" + }, + { + "name": "lcobucci/jwt", + "version": "5.2.0", + "source": { + "type": "git", + "url": "https://github.com/lcobucci/jwt.git", + "reference": "0ba88aed12c04bd2ed9924f500673f32b67a6211" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lcobucci/jwt/zipball/0ba88aed12c04bd2ed9924f500673f32b67a6211", + "reference": "0ba88aed12c04bd2ed9924f500673f32b67a6211", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "ext-sodium": "*", + "php": "~8.1.0 || ~8.2.0 || ~8.3.0", + "psr/clock": "^1.0" + }, + "require-dev": { + "infection/infection": "^0.27.0", + "lcobucci/clock": "^3.0", + "lcobucci/coding-standard": "^11.0", + "phpbench/phpbench": "^1.2.9", + "phpstan/extension-installer": "^1.2", + "phpstan/phpstan": "^1.10.7", + "phpstan/phpstan-deprecation-rules": "^1.1.3", + "phpstan/phpstan-phpunit": "^1.3.10", + "phpstan/phpstan-strict-rules": "^1.5.0", + "phpunit/phpunit": "^10.2.6" + }, + "suggest": { + "lcobucci/clock": ">= 3.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Lcobucci\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Luís Cobucci", + "email": "lcobucci@gmail.com", + "role": "Developer" + } + ], + "description": "A simple library to work with JSON Web Token and JSON Web Signature", + "keywords": [ + "JWS", + "jwt" + ], + "support": { + "issues": "https://github.com/lcobucci/jwt/issues", + "source": "https://github.com/lcobucci/jwt/tree/5.2.0" + }, + "funding": [ + { + "url": "https://github.com/lcobucci", + "type": "github" + }, + { + "url": "https://www.patreon.com/lcobucci", + "type": "patreon" + } + ], + "time": "2023-11-20T21:17:42+00:00" + }, + { + "name": "lexik/jwt-authentication-bundle", + "version": "v2.20.3", + "source": { + "type": "git", + "url": "https://github.com/lexik/LexikJWTAuthenticationBundle.git", + "reference": "a196d68d07dd5486a523cc3415620badbb5d25c2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lexik/LexikJWTAuthenticationBundle/zipball/a196d68d07dd5486a523cc3415620badbb5d25c2", + "reference": "a196d68d07dd5486a523cc3415620badbb5d25c2", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "lcobucci/clock": "^1.2|^2.0|^3.0", + "lcobucci/jwt": "^3.4|^4.1|^5.0", + "namshi/jose": "^7.2", + "php": ">=7.1", + "symfony/config": "^4.4|^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^4.4|^5.4|^6.0|^7.0", + "symfony/deprecation-contracts": "^2.4|^3.0", + "symfony/event-dispatcher": "^4.4|^5.4|^6.0|^7.0", + "symfony/http-foundation": "^4.4|^5.4|^6.0|^7.0", + "symfony/http-kernel": "^4.4|^5.4|^6.0|^7.0", + "symfony/property-access": "^4.4|^5.4|^6.0|^7.0", + "symfony/security-bundle": "^4.4|^5.4|^6.0|^7.0", + "symfony/translation-contracts": "^1.0|^2.0|^3.0" + }, + "conflict": { + "symfony/console": "<4.4" + }, + "require-dev": { + "symfony/browser-kit": "^5.4|^6.0|^7.0", + "symfony/console": "^4.4|^5.4|^6.0|^7.0", + "symfony/dom-crawler": "^5.4|^6.0|^7.0", + "symfony/filesystem": "^4.4|^5.4|^6.0|^7.0", + "symfony/framework-bundle": "^4.4|^5.4|^6.0|^7.0", + "symfony/phpunit-bridge": "^4.4|^5.4|^6.0|^7.0", + "symfony/security-guard": "^4.4|^5.4|^6.0|^7.0", + "symfony/var-dumper": "^4.4|^5.4|^6.0|^7.0", + "symfony/yaml": "^4.4|^5.4|^6.0|^7.0" + }, + "suggest": { + "gesdinet/jwt-refresh-token-bundle": "Implements a refresh token system over Json Web Tokens in Symfony", + "spomky-labs/lexik-jose-bridge": "Provides a JWT Token encoder with encryption support" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Lexik\\Bundle\\JWTAuthenticationBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jeremy Barthe", + "email": "j.barthe@lexik.fr", + "homepage": "https://github.com/jeremyb" + }, + { + "name": "Nicolas Cabot", + "email": "n.cabot@lexik.fr", + "homepage": "https://github.com/slashfan" + }, + { + "name": "Cedric Girard", + "email": "c.girard@lexik.fr", + "homepage": "https://github.com/cedric-g" + }, + { + "name": "Dev Lexik", + "email": "dev@lexik.fr", + "homepage": "https://github.com/lexik" + }, + { + "name": "Robin Chalas", + "email": "robin.chalas@gmail.com", + "homepage": "https://github.com/chalasr" + }, + { + "name": "Lexik Community", + "homepage": "https://github.com/lexik/LexikJWTAuthenticationBundle/graphs/contributors" + } + ], + "description": "This bundle provides JWT authentication for your Symfony REST API", + "homepage": "https://github.com/lexik/LexikJWTAuthenticationBundle", + "keywords": [ + "Authentication", + "JWS", + "api", + "bundle", + "jwt", + "rest", + "symfony" + ], + "support": { + "issues": "https://github.com/lexik/LexikJWTAuthenticationBundle/issues", + "source": "https://github.com/lexik/LexikJWTAuthenticationBundle/tree/v2.20.3" + }, + "funding": [ + { + "url": "https://github.com/chalasr", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/lexik/jwt-authentication-bundle", + "type": "tidelift" + } + ], + "time": "2023-12-14T15:58:11+00:00" + }, { "name": "monolog/monolog", "version": "3.5.0", @@ -1473,6 +1729,73 @@ ], "time": "2023-10-27T15:32:31+00:00" }, + { + "name": "namshi/jose", + "version": "7.2.3", + "source": { + "type": "git", + "url": "https://github.com/namshi/jose.git", + "reference": "89a24d7eb3040e285dd5925fcad992378b82bcff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/namshi/jose/zipball/89a24d7eb3040e285dd5925fcad992378b82bcff", + "reference": "89a24d7eb3040e285dd5925fcad992378b82bcff", + "shasum": "" + }, + "require": { + "ext-date": "*", + "ext-hash": "*", + "ext-json": "*", + "ext-pcre": "*", + "ext-spl": "*", + "php": ">=5.5", + "symfony/polyfill-php56": "^1.0" + }, + "require-dev": { + "phpseclib/phpseclib": "^2.0", + "phpunit/phpunit": "^4.5|^5.0", + "satooshi/php-coveralls": "^1.0" + }, + "suggest": { + "ext-openssl": "Allows to use OpenSSL as crypto engine.", + "phpseclib/phpseclib": "Allows to use Phpseclib as crypto engine, use version ^2.0." + }, + "type": "library", + "autoload": { + "psr-4": { + "Namshi\\JOSE\\": "src/Namshi/JOSE/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alessandro Nadalin", + "email": "alessandro.nadalin@gmail.com" + }, + { + "name": "Alessandro Cinelli (cirpo)", + "email": "alessandro.cinelli@gmail.com" + } + ], + "description": "JSON Object Signing and Encryption library for PHP.", + "keywords": [ + "JSON Web Signature", + "JSON Web Token", + "JWS", + "json", + "jwt", + "token" + ], + "support": { + "issues": "https://github.com/namshi/jose/issues", + "source": "https://github.com/namshi/jose/tree/master" + }, + "time": "2016-12-05T07:27:31+00:00" + }, { "name": "phpdocumentor/reflection-common", "version": "2.2.0", @@ -5155,6 +5478,74 @@ ], "time": "2024-01-29T20:11:03+00:00" }, + { + "name": "symfony/polyfill-php56", + "version": "v1.20.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php56.git", + "reference": "54b8cd7e6c1643d78d011f3be89f3ef1f9f4c675" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/54b8cd7e6c1643d78d011f3be89f3ef1f9f4c675", + "reference": "54b8cd7e6c1643d78d011f3be89f3ef1f9f4c675", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "metapackage", + "extra": { + "branch-alias": { + "dev-main": "1.20-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 5.6+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php56/tree/v1.20.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-10-23T14:02:19+00:00" + }, { "name": "symfony/polyfill-php83", "version": "v1.29.0", diff --git a/backend/config/bundles.php b/backend/config/bundles.php index 4e3a560..6dc096a 100644 --- a/backend/config/bundles.php +++ b/backend/config/bundles.php @@ -13,4 +13,5 @@ Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true], Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true], + Lexik\Bundle\JWTAuthenticationBundle\LexikJWTAuthenticationBundle::class => ['all' => true], ]; diff --git a/backend/symfony.lock b/backend/symfony.lock index 2769bd4..42b55a7 100644 --- a/backend/symfony.lock +++ b/backend/symfony.lock @@ -26,6 +26,18 @@ "migrations/.gitignore" ] }, + "lexik/jwt-authentication-bundle": { + "version": "2.20", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "2.5", + "ref": "e9481b233a11ef7e15fe055a2b21fd3ac1aa2bb7" + }, + "files": [ + "config/packages/lexik_jwt_authentication.yaml" + ] + }, "phpunit/phpunit": { "version": "9.6", "recipe": { From 880cea4c735f8dd27abfb70d6145725d23d394c2 Mon Sep 17 00:00:00 2001 From: mploierMacBook Date: Mon, 15 Apr 2024 09:32:33 +0200 Subject: [PATCH 09/12] feat: return JWT-Token after authentication --- backend/composer.json | 2 + backend/src/Controller/LoginController.php | 18 +++++++-- backend/src/Entity/AuthToken.php | 47 ++++++++++++++++++---- 3 files changed, 56 insertions(+), 11 deletions(-) diff --git a/backend/composer.json b/backend/composer.json index b28f468..0f08be0 100644 --- a/backend/composer.json +++ b/backend/composer.json @@ -12,6 +12,7 @@ "doctrine/doctrine-migrations-bundle": "^3.3", "doctrine/orm": "^3.1", "lexik/jwt-authentication-bundle": "^2.20", + "nixilla/php-jwt": "^0.1.1", "phpdocumentor/reflection-docblock": "^5.3", "phpstan/phpdoc-parser": "^1.26", "symfony/asset": "7.0.*", @@ -25,6 +26,7 @@ "symfony/framework-bundle": "7.0.*", "symfony/http-client": "7.0.*", "symfony/intl": "7.0.*", + "symfony/ldap": "7.0.*", "symfony/mailer": "7.0.*", "symfony/mime": "7.0.*", "symfony/monolog-bundle": "^3.0", diff --git a/backend/src/Controller/LoginController.php b/backend/src/Controller/LoginController.php index 85875ee..205ceeb 100644 --- a/backend/src/Controller/LoginController.php +++ b/backend/src/Controller/LoginController.php @@ -3,23 +3,35 @@ namespace App\Controller; use App\Entity\AuthToken; +use App\Kernel; use App\Service\AuthService; +use Lexik\Bundle\JWTAuthenticationBundle\Encoder\JWTEncoderInterface; +use Lexik\Bundle\JWTAuthenticationBundle\Event\JWTDecodedEvent; +use Lexik\Bundle\JWTAuthenticationBundle\Event\JWTEncodedEvent; +use Lexik\Bundle\JWTAuthenticationBundle\Security\Authentication\Token\JWTUserToken; +use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTManager; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; +use function Symfony\Component\DependencyInjection\Loader\Configurator\param; class LoginController extends AbstractController { #[Route('/ldaps', name: 'app_ldap')] - public function index(AuthService $authService, Request $request): Response + public function index(AuthService $authService, Request $request, Kernel $kernel): Response { $user = $request->get("usr"); $pwd = $request->get("pwd"); - $return = new AuthToken($authService->authenticateUser($user, $pwd)); + $status =$authService->authenticateUser($user, $pwd); + $key = file_get_contents($kernel->getProjectDir() . "/config/jwt/private.pem"); + $token = new AuthToken($key); + $token->setValue(['user'=>$user, 'authorized'=>$status]); - return new JsonResponse(json_encode($return), 200, [], true); + + + return new JsonResponse($token, 200, [], true); } } diff --git a/backend/src/Entity/AuthToken.php b/backend/src/Entity/AuthToken.php index 6d2da99..a4d7950 100644 --- a/backend/src/Entity/AuthToken.php +++ b/backend/src/Entity/AuthToken.php @@ -2,31 +2,36 @@ namespace App\Entity; +use Exception; +use Lexik\Bundle\JWTAuthenticationBundle\Encoder\JWTEncoderInterface; +use Lexik\Bundle\JWTAuthenticationBundle\Exception\JWTEncodeFailureException; +use Lexik\Bundle\JWTAuthenticationBundle\Exception\JWTDecodeFailureException; +use JWT\Authentication\JWT; use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator; class AuthToken { - public String $value; + private $key; + public String $jwtString; public bool $success; /** - * @param bool $validation + * @param $key */ - public function __construct(bool $validation) + public function __construct($key) { - $this->value = uniqid(); - $this->success = $validation; + $this->key = $key; } public function getValue(): string { - return $this->value; + return $this->jwtString; } - public function setValue(string $value): void + public function setValue(array $payload): void { - $this->value = $value; + $this->jwtString = $this->encode($payload); } public function isSuccess(): bool @@ -40,4 +45,30 @@ public function setSuccess(bool $success): void } + private function encode(array $data): string + { + try { + $data = array_merge($data, ['iat' => (int)date('U')]); + return JWT::encode($data, $this->key); + } + catch (Exception $e) { + throw new JWTEncodeFailureException(JWTEncodeFailureException::INVALID_CONFIG, 'An error occurred while trying to encode the JWT token.', $e); + } + } + + public function decode($token): array + { + try { + return (array) JWT::decode($token, $this->key); + } catch (Exception $e) { + throw new JWTDecodeFailureException(JWTDecodeFailureException::INVALID_TOKEN, 'Invalid JWT Token', $e); + } + } + + public function __toString(): string + { + return $this->jwtString; + } + + } \ No newline at end of file From ffb0683142cf668e2edc8d97f6a93b3c7c8f6508 Mon Sep 17 00:00:00 2001 From: mploierMacBook Date: Mon, 15 Apr 2024 09:35:39 +0200 Subject: [PATCH 10/12] refactor: specified variable data type --- backend/src/Entity/AuthToken.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/Entity/AuthToken.php b/backend/src/Entity/AuthToken.php index a4d7950..a5df607 100644 --- a/backend/src/Entity/AuthToken.php +++ b/backend/src/Entity/AuthToken.php @@ -11,7 +11,7 @@ class AuthToken { - private $key; + private String $key; public String $jwtString; public bool $success; From ec5ae96407eecc7e2404a147805a1383161ee03e Mon Sep 17 00:00:00 2001 From: mploierMacBook Date: Mon, 15 Apr 2024 09:50:43 +0200 Subject: [PATCH 11/12] refactor: optimized imports --- backend/src/Controller/LoginController.php | 6 ------ backend/src/Entity/AuthToken.php | 4 +--- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/backend/src/Controller/LoginController.php b/backend/src/Controller/LoginController.php index 205ceeb..f43eee3 100644 --- a/backend/src/Controller/LoginController.php +++ b/backend/src/Controller/LoginController.php @@ -5,17 +5,11 @@ use App\Entity\AuthToken; use App\Kernel; use App\Service\AuthService; -use Lexik\Bundle\JWTAuthenticationBundle\Encoder\JWTEncoderInterface; -use Lexik\Bundle\JWTAuthenticationBundle\Event\JWTDecodedEvent; -use Lexik\Bundle\JWTAuthenticationBundle\Event\JWTEncodedEvent; -use Lexik\Bundle\JWTAuthenticationBundle\Security\Authentication\Token\JWTUserToken; -use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTManager; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; -use function Symfony\Component\DependencyInjection\Loader\Configurator\param; class LoginController extends AbstractController { diff --git a/backend/src/Entity/AuthToken.php b/backend/src/Entity/AuthToken.php index a5df607..d646020 100644 --- a/backend/src/Entity/AuthToken.php +++ b/backend/src/Entity/AuthToken.php @@ -3,11 +3,9 @@ namespace App\Entity; use Exception; -use Lexik\Bundle\JWTAuthenticationBundle\Encoder\JWTEncoderInterface; use Lexik\Bundle\JWTAuthenticationBundle\Exception\JWTEncodeFailureException; use Lexik\Bundle\JWTAuthenticationBundle\Exception\JWTDecodeFailureException; use JWT\Authentication\JWT; -use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator; class AuthToken { @@ -71,4 +69,4 @@ public function __toString(): string } -} \ No newline at end of file +} From a4c688f8e77d711dfac3d31fb03908278b60335f Mon Sep 17 00:00:00 2001 From: mploierMacBook Date: Mon, 15 Apr 2024 11:05:48 +0200 Subject: [PATCH 12/12] docs: write docs for ldap in english and german --- docs/de/developers/ldap.md | 182 ++++++++++++++++++++++++++++++++++++- docs/developers/ldap.md | 180 +++++++++++++++++++++++++++++++++++- 2 files changed, 360 insertions(+), 2 deletions(-) diff --git a/docs/de/developers/ldap.md b/docs/de/developers/ldap.md index 1b1be72..f42d33d 100644 --- a/docs/de/developers/ldap.md +++ b/docs/de/developers/ldap.md @@ -1,3 +1,183 @@ # LDAP +::: info +Die LDAP-Authentifizierung verbindet sich mit dem Server, der in der .env-Datei angegeben ist, und versucht +den angegebenen Benutzer in Kombination mit dem angegebenen Passwort zu authentifizieren. Die Authentifizierung wird +eine Rückmeldung [JWT](https://jwt.io). +::: + +## LoginController Dokumentation + +### Übersicht +Der `LoginController` ist ein Symfony-Controller, der für die Bearbeitung von Authentifizierungsanfragen zuständig ist. Er enthält eine Action +Methode `index()`, die auf die Route `/ldaps` abgebildet ist. Diese authentifiziert Benutzer und generiert dementsprechende Authentifizierungs-Token. + +### Code Auszug +```php +get("usr"); + $pwd = $request->get("pwd"); + $status =$authService->authenticateUser($user, $pwd); + + $key = file_get_contents($kernel->getProjectDir() . "/config/jwt/private.pem"); + $token = new AuthToken($key); + $token->setValue(['user'=>$user, 'authorized'=>$status]); + + return new JsonResponse($token, 200, [], true); + } +} +``` + +### Funktionalität ++ **Authentifizierung**: Es akzeptiert die Parameter Benutzername (usr) und Passwort (pwd) aus der Anfrage und authentifiziert den Benutzer + unter Verwendung einer Instanz von AuthService. ++ **Token-Generierung**: Nach erfolgreicher Authentifizierung wird ein Authentifizierungs-Token mithilfe der AuthToken-Klasse erzeugt und + und gibt es als JSON-Antwort zurück. ++ **Route**: Die Aktionsmethode wird auf die /ldaps-Route abgebildet. + + +## AuthService Dokumentation + +### Übersicht +Die Klasse `AuthService` bietet Funktionen zur Authentifizierung von Benutzern gegenüber einem LDAP-Server. + +### Code Auszug +```php + +``` + +### Funktionalität ++ **LDAP-Verbindung**: Er stellt eine Verbindung zu dem in der Umgebungsvariablen `LDAP_URL` angegebenen LDAP-Server her. ++ **Authentifizierung**: Es wird versucht, sich mit den angegebenen Benutzerdaten ($user und $password) innerhalb der angegebenen LDAP-Basis an den LDAP-Server zu binden. ++ **Fehlerbehandlung**: Es fängt alle Ausnahmen ab, die während des Authentifizierungsprozesses auftreten, und gibt im Falle eines Fehlers `false` zurück. + + +## AuthToken Dokumentation + +### Übersicht +Die Klasse `AuthentToken` ist für die Kodierung und Dekodierung von JSON-Web-Tokens (JWTs) unter Verwendung eines angegebenen Schlüssels zuständig. + +### Code Auszug +```php +key = $key; + } + + + public function getValue(): string + { + return $this->jwtString; + } + + public function setValue(array $payload): void + { + $this->jwtString = $this->encode($payload); + } + + public function isSuccess(): bool + { + return $this->success; + } + + public function setSuccess(bool $success): void + { + $this->success = $success; + } + + + private function encode(array $data): string + { + try { + $data = array_merge($data, ['iat' => (int)date('U')]); + return JWT::encode($data, $this->key); + } + catch (Exception $e) { + throw new JWTEncodeFailureException(JWTEncodeFailureException::INVALID_CONFIG, 'An error occurred while trying to encode the JWT token.', $e); + } + } + + public function decode($token): array + { + try { + return (array) JWT::decode($token, $this->key); + } catch (Exception $e) { + throw new JWTDecodeFailureException(JWTDecodeFailureException::INVALID_TOKEN, 'Invalid JWT Token', $e); + } + } + + public function __toString(): string + { + return $this->jwtString; + } + + +} +?> +``` + +### Functionalist ++ **Token-Kodierung**: Es kodiert eine Nutzlast in ein JWT unter Verwendung des angegebenen Schlüssels. ++ **Token-Dekodierung**: Dekodiert ein JWT-Token unter Verwendung des angegebenen Schlüssels. ++ **Ausnahmebehandlung**: Es fängt Ausnahmen während der Kodierungs- und Dekodierungsprozesse ab und löst entsprechende Ausnahmen aus. -::: danger WORK IN PROGRESS diff --git a/docs/developers/ldap.md b/docs/developers/ldap.md index 1b1be72..dc89617 100644 --- a/docs/developers/ldap.md +++ b/docs/developers/ldap.md @@ -1,3 +1,181 @@ # LDAP +::: info +LDAP authentication will connect to the server which is declared in the .env file and try +to authenticate the given user in combination with the given password. The authentication will +return a [JWT](https://jwt.io). +::: -::: danger WORK IN PROGRESS +## LoginController Documentation + +### Overview +The `LoginController` is a Symfony controller responsible for handling authentication requests. It contains an action +method `index()` mapped to the route `/ldaps`, which authenticates users and generates authentication tokens. + +### Code Breakdown +```php +get("usr"); + $pwd = $request->get("pwd"); + $status =$authService->authenticateUser($user, $pwd); + + $key = file_get_contents($kernel->getProjectDir() . "/config/jwt/private.pem"); + $token = new AuthToken($key); + $token->setValue(['user'=>$user, 'authorized'=>$status]); + + return new JsonResponse($token, 200, [], true); + } +} +``` + +### Functionality ++ **Authentication**: It accepts username (usr) and password (pwd) parameters from the request and authenticates the user + using an instance of AuthService. ++ **Token Generation**: Upon successful authentication, it generates an authentication token using the AuthToken class and + returns it as a JSON response. ++ **Route**: The action method is mapped to the /ldaps route. + + +## AuthService Documentation + +### Overview +The `AuthService` class provides functionality for authenticating users against an LDAP server. + +### Code Breakdown +```php + +``` + +### Functionality ++ **LDAP Connection**: It establishes a connection to the LDAP server specified in the environment variable LDAP_URL. ++ **Authentication**: It attempts to bind to the LDAP server using the provided user credentials ($user and $password) within the specified LDAP base. ++ **Error Handling**: It catches any exceptions that occur during the authentication process and returns false in case of failure. + +## AuthToken Documentation + +### Overview +The `AuthToken` class is responsible for encoding and decoding JSON Web Tokens (JWTs) using a provided key. + +### Code Breakdown +```php +key = $key; + } + + + public function getValue(): string + { + return $this->jwtString; + } + + public function setValue(array $payload): void + { + $this->jwtString = $this->encode($payload); + } + + public function isSuccess(): bool + { + return $this->success; + } + + public function setSuccess(bool $success): void + { + $this->success = $success; + } + + + private function encode(array $data): string + { + try { + $data = array_merge($data, ['iat' => (int)date('U')]); + return JWT::encode($data, $this->key); + } + catch (Exception $e) { + throw new JWTEncodeFailureException(JWTEncodeFailureException::INVALID_CONFIG, 'An error occurred while trying to encode the JWT token.', $e); + } + } + + public function decode($token): array + { + try { + return (array) JWT::decode($token, $this->key); + } catch (Exception $e) { + throw new JWTDecodeFailureException(JWTDecodeFailureException::INVALID_TOKEN, 'Invalid JWT Token', $e); + } + } + + public function __toString(): string + { + return $this->jwtString; + } + + +} +?> +``` + +### Functionality ++ **Token Encoding**: It encodes a payload into a JWT using the provided key. ++ **Token Decoding**: It decodes a JWT token using the provided key. ++ **Exception Handling**: It catches exceptions during encoding and decoding processes and throws appropriate exceptions.