Compare commits
13 Commits
f378751f7a
...
issue-4707
Author | SHA1 | Date | |
---|---|---|---|
f007dcf6d8 | |||
075be9b0df | |||
4e4c5d8e7b | |||
7032787d8c | |||
999e708ff7 | |||
cb8361e7d1 | |||
e3f406a8bb | |||
d6d9e81df6 | |||
8e56433216 | |||
19178bbe3b | |||
14668150cb | |||
0903151f27 | |||
f39ab1626e |
@ -20,6 +20,7 @@
|
||||
"symfony/form": "5.4.*",
|
||||
"symfony/framework-bundle": "5.4.*",
|
||||
"symfony/http-client": "5.4.*",
|
||||
"symfony/monolog-bundle": "^3.10",
|
||||
"symfony/rate-limiter": "5.4.*",
|
||||
"symfony/runtime": "5.4.*",
|
||||
"symfony/security-bundle": "5.4.*",
|
||||
|
269
composer.lock
generated
269
composer.lock
generated
@ -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": "203398b3a4f3ff689ff3341c02460f23",
|
||||
"content-hash": "9daf21762ed80ef11e74a53f5d27119f",
|
||||
"packages": [
|
||||
{
|
||||
"name": "clue/stream-filter",
|
||||
@ -589,6 +589,108 @@
|
||||
},
|
||||
"time": "2024-03-08T09:58:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "monolog/monolog",
|
||||
"version": "2.10.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Seldaek/monolog.git",
|
||||
"reference": "5cf826f2991858b54d5c3809bee745560a1042a7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/5cf826f2991858b54d5c3809bee745560a1042a7",
|
||||
"reference": "5cf826f2991858b54d5c3809bee745560a1042a7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2",
|
||||
"psr/log": "^1.0.1 || ^2.0 || ^3.0"
|
||||
},
|
||||
"provide": {
|
||||
"psr/log-implementation": "1.0.0 || 2.0.0 || 3.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"aws/aws-sdk-php": "^2.4.9 || ^3.0",
|
||||
"doctrine/couchdb": "~1.0@dev",
|
||||
"elasticsearch/elasticsearch": "^7 || ^8",
|
||||
"ext-json": "*",
|
||||
"graylog2/gelf-php": "^1.4.2 || ^2@dev",
|
||||
"guzzlehttp/guzzle": "^7.4",
|
||||
"guzzlehttp/psr7": "^2.2",
|
||||
"mongodb/mongodb": "^1.8",
|
||||
"php-amqplib/php-amqplib": "~2.4 || ^3",
|
||||
"phpspec/prophecy": "^1.15",
|
||||
"phpstan/phpstan": "^1.10",
|
||||
"phpunit/phpunit": "^8.5.38 || ^9.6.19",
|
||||
"predis/predis": "^1.1 || ^2.0",
|
||||
"rollbar/rollbar": "^1.3 || ^2 || ^3",
|
||||
"ruflin/elastica": "^7",
|
||||
"swiftmailer/swiftmailer": "^5.3|^6.0",
|
||||
"symfony/mailer": "^5.4 || ^6",
|
||||
"symfony/mime": "^5.4 || ^6"
|
||||
},
|
||||
"suggest": {
|
||||
"aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
|
||||
"doctrine/couchdb": "Allow sending log messages to a CouchDB server",
|
||||
"elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client",
|
||||
"ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
|
||||
"ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler",
|
||||
"ext-mbstring": "Allow to work properly with unicode symbols",
|
||||
"ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)",
|
||||
"ext-openssl": "Required to send log messages using SSL",
|
||||
"ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)",
|
||||
"graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server",
|
||||
"mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)",
|
||||
"php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib",
|
||||
"rollbar/rollbar": "Allow sending log messages to Rollbar",
|
||||
"ruflin/elastica": "Allow sending log messages to an Elastic Search server"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "2.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Monolog\\": "src/Monolog"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jordi Boggiano",
|
||||
"email": "j.boggiano@seld.be",
|
||||
"homepage": "https://seld.be"
|
||||
}
|
||||
],
|
||||
"description": "Sends your logs to files, sockets, inboxes, databases and various web services",
|
||||
"homepage": "https://github.com/Seldaek/monolog",
|
||||
"keywords": [
|
||||
"log",
|
||||
"logging",
|
||||
"psr-3"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/Seldaek/monolog/issues",
|
||||
"source": "https://github.com/Seldaek/monolog/tree/2.10.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/Seldaek",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/monolog/monolog",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-11-12T12:43:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "php-http/client-common",
|
||||
"version": "2.7.2",
|
||||
@ -3566,6 +3668,171 @@
|
||||
],
|
||||
"time": "2024-05-31T14:33:22+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/monolog-bridge",
|
||||
"version": "v5.4.45",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/monolog-bridge.git",
|
||||
"reference": "cf7d75d4d64a41fbb1c0e92301bec404134fa84b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/cf7d75d4d64a41fbb1c0e92301bec404134fa84b",
|
||||
"reference": "cf7d75d4d64a41fbb1c0e92301bec404134fa84b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"monolog/monolog": "^1.25.1|^2",
|
||||
"php": ">=7.2.5",
|
||||
"symfony/deprecation-contracts": "^2.1|^3",
|
||||
"symfony/http-kernel": "^5.3|^6.0",
|
||||
"symfony/polyfill-php80": "^1.16",
|
||||
"symfony/service-contracts": "^1.1|^2|^3"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/console": "<4.4",
|
||||
"symfony/http-foundation": "<5.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/console": "^4.4|^5.0|^6.0",
|
||||
"symfony/http-client": "^4.4|^5.0|^6.0",
|
||||
"symfony/mailer": "^4.4|^5.0|^6.0",
|
||||
"symfony/messenger": "^4.4|^5.0|^6.0",
|
||||
"symfony/mime": "^4.4|^5.0|^6.0",
|
||||
"symfony/security-core": "^4.4|^5.0|^6.0",
|
||||
"symfony/var-dumper": "^4.4|^5.0|^6.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/console": "For the possibility to show log messages in console commands depending on verbosity settings.",
|
||||
"symfony/http-kernel": "For using the debugging handlers together with the response life cycle of the HTTP kernel.",
|
||||
"symfony/var-dumper": "For using the debugging handlers like the console handler or the log server handler."
|
||||
},
|
||||
"type": "symfony-bridge",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Bridge\\Monolog\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Provides integration for Monolog with various Symfony components",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/monolog-bridge/tree/v5.4.45"
|
||||
},
|
||||
"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": "2024-10-10T06:37:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/monolog-bundle",
|
||||
"version": "v3.10.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/monolog-bundle.git",
|
||||
"reference": "414f951743f4aa1fd0f5bf6a0e9c16af3fe7f181"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/414f951743f4aa1fd0f5bf6a0e9c16af3fe7f181",
|
||||
"reference": "414f951743f4aa1fd0f5bf6a0e9c16af3fe7f181",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"monolog/monolog": "^1.25.1 || ^2.0 || ^3.0",
|
||||
"php": ">=7.2.5",
|
||||
"symfony/config": "^5.4 || ^6.0 || ^7.0",
|
||||
"symfony/dependency-injection": "^5.4 || ^6.0 || ^7.0",
|
||||
"symfony/http-kernel": "^5.4 || ^6.0 || ^7.0",
|
||||
"symfony/monolog-bridge": "^5.4 || ^6.0 || ^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/console": "^5.4 || ^6.0 || ^7.0",
|
||||
"symfony/phpunit-bridge": "^6.3 || ^7.0",
|
||||
"symfony/yaml": "^5.4 || ^6.0 || ^7.0"
|
||||
},
|
||||
"type": "symfony-bundle",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Bundle\\MonologBundle\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony MonologBundle",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"log",
|
||||
"logging"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/symfony/monolog-bundle/issues",
|
||||
"source": "https://github.com/symfony/monolog-bundle/tree/v3.10.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": "2023-11-06T17:08:13+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/options-resolver",
|
||||
"version": "v5.4.40",
|
||||
|
@ -8,4 +8,5 @@ return [
|
||||
Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => ['all' => true],
|
||||
Sentry\SentryBundle\SentryBundle::class => ['all' => true],
|
||||
Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true],
|
||||
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
|
||||
];
|
||||
|
6
config/packages/monolog.yaml
Normal file
6
config/packages/monolog.yaml
Normal file
@ -0,0 +1,6 @@
|
||||
monolog:
|
||||
handlers:
|
||||
stdout:
|
||||
type: stream
|
||||
path: "php://stdout"
|
||||
level: "%env(string:LOGGER_LEVEL)%"
|
@ -29,6 +29,9 @@ parameters:
|
||||
|
||||
env(PEPPER): ~
|
||||
pepper: '%env(resolve:PEPPER)%'
|
||||
|
||||
env(LOGGER_LEVEL): "info"
|
||||
|
||||
services:
|
||||
# default configuration for services in *this* file
|
||||
_defaults:
|
||||
|
@ -13,7 +13,7 @@ services:
|
||||
ports:
|
||||
- 8082:8071
|
||||
volumes:
|
||||
- .:/app
|
||||
- .:/app
|
||||
tmpfs:
|
||||
- /var/www/var/logs:uid=${FIXUID:-1000},gid=${FIXGID:-1000}
|
||||
- /var/www/var/cache:uid=${FIXUID:-1000},gid=${FIXGID:-1000}
|
||||
@ -40,6 +40,9 @@ services:
|
||||
- HASH_ALGO_LEGACY="sha256"
|
||||
- SECURITY_PATTERN=password,salt,pepper
|
||||
- CADDY_HTTP_PORT=8071
|
||||
- LOGGER_LEVEL=info
|
||||
- PHP_FPM_DISPLAY_ERRORS=on
|
||||
- PHP_FPM_CATCH_WORKERS_OUTPUT=1
|
||||
|
||||
oidc-test:
|
||||
image: bornholm/oidc-test:v0.0.0-1-g936a77e
|
||||
|
@ -10,7 +10,8 @@ ARG ADDITIONAL_PACKAGES="bash=5.2.15-r0 \
|
||||
php81-soap=${PHP_PKG_VERSION} \
|
||||
php81-ldap=${PHP_PKG_VERSION} \
|
||||
php81-pdo_mysql=${PHP_PKG_VERSION} \
|
||||
php81-bcmath=${PHP_PKG_VERSION}"
|
||||
php81-bcmath=${PHP_PKG_VERSION} \
|
||||
php81-pecl-xdebug"
|
||||
|
||||
FROM reg.cadoles.com/cadoles/symfony:alpine-php-8.1-base-2024.7.25-stable.959.7896915
|
||||
FROM reg.cadoles.com/cadoles/symfony:alpine-php-8.1-base-2024.10.4-stable.1529.b630c69
|
||||
RUN chown 1000:www-data -R /app
|
||||
|
@ -10,8 +10,9 @@ ARG ADDITIONAL_PACKAGES="bash=5.2.15-r0 \
|
||||
php81-soap=${PHP_PKG_VERSION} \
|
||||
php81-ldap=${PHP_PKG_VERSION} \
|
||||
php81-pdo_mysql=${PHP_PKG_VERSION} \
|
||||
php81-bcmath=${PHP_PKG_VERSION}"
|
||||
php81-bcmath=${PHP_PKG_VERSION} \
|
||||
php81-pecl-xdebug"
|
||||
|
||||
FROM reg.cadoles.com/cadoles/symfony:alpine-php-8.1-standalone-2024.7.25-stable.959.7896915
|
||||
FROM reg.cadoles.com/cadoles/symfony:alpine-php-8.1-standalone-2024.10.4-stable.1529.b630c69
|
||||
RUN chown 1000:www-data -R /app
|
||||
USER www-data
|
||||
|
@ -32,21 +32,9 @@ class SecurityController extends AbstractController
|
||||
$loginForm->addError(new FormError($trans->trans('error.login', [], 'messages')));
|
||||
$request->getSession()->remove(SQLLoginUserAuthenticator::ERROR_LOGIN);
|
||||
}
|
||||
if ($request->getSession()->has(SQLLoginUserAuthenticator::ERROR_PDO)) {
|
||||
$loginForm->addError(new FormError($trans->trans('error.pdo', [], 'messages')));
|
||||
$request->getSession()->remove(SQLLoginUserAuthenticator::ERROR_PDO);
|
||||
}
|
||||
if ($request->getSession()->has(SQLLoginUserAuthenticator::ERROR_CONFIGURATION)) {
|
||||
$loginForm->addError(new FormError($trans->trans('error.configuration', [], 'messages')));
|
||||
$request->getSession()->remove(SQLLoginUserAuthenticator::ERROR_CONFIGURATION);
|
||||
}
|
||||
if ($request->getSession()->has(SQLLoginUserAuthenticator::ERROR_DATA_TO_FETCH_CONFIGURATION)) {
|
||||
$loginForm->addError(new FormError($trans->trans('error.data_to_fetch_configuration', [], 'messages')));
|
||||
$request->getSession()->remove(SQLLoginUserAuthenticator::ERROR_DATA_TO_FETCH_CONFIGURATION);
|
||||
}
|
||||
if ($request->getSession()->has(SQLLoginUserAuthenticator::ERROR_SECURITY_PATTERN_CONFIGURATION)) {
|
||||
$loginForm->addError(new FormError($trans->trans('error.security_pattern_configuration', [], 'messages')));
|
||||
$request->getSession()->remove(SQLLoginUserAuthenticator::ERROR_SECURITY_PATTERN_CONFIGURATION);
|
||||
if ($request->getSession()->has(SQLLoginUserAuthenticator::TECHNICAL_ERROR)) {
|
||||
$loginForm->addError(new FormError($trans->trans('error.technical', [], 'messages')));
|
||||
$request->getSession()->remove(SQLLoginUserAuthenticator::TECHNICAL_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,14 +3,20 @@
|
||||
namespace App\Hydra;
|
||||
|
||||
use App\Hydra\Exception\InvalidChallengeException;
|
||||
use Exception;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
use Symfony\Contracts\HttpClient\ResponseInterface;
|
||||
|
||||
class Client
|
||||
{
|
||||
protected $client;
|
||||
|
||||
protected $hydraAdminBaseUrl;
|
||||
private HttpClientInterface $client;
|
||||
private const MAX_RETRY = 3;
|
||||
private const SLEEP_TIME = [
|
||||
5,
|
||||
500,
|
||||
5000,
|
||||
];
|
||||
private string $hydraAdminBaseUrl;
|
||||
|
||||
public function __construct(HttpClientInterface $client, string $hydraAdminBaseUrl)
|
||||
{
|
||||
@ -22,11 +28,11 @@ class Client
|
||||
{
|
||||
$response = $this->client->request(
|
||||
'GET',
|
||||
$this->hydraAdminBaseUrl . '/oauth2/auth/requests/login',
|
||||
$this->hydraAdminBaseUrl.'/oauth2/auth/requests/login',
|
||||
[
|
||||
'query' => [
|
||||
'login_challenge' => $loginChallenge,
|
||||
]
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
@ -35,7 +41,6 @@ class Client
|
||||
throw new InvalidChallengeException();
|
||||
}
|
||||
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
@ -43,11 +48,11 @@ class Client
|
||||
{
|
||||
$response = $this->client->request(
|
||||
'GET',
|
||||
$this->hydraAdminBaseUrl . '/oauth2/auth/requests/logout',
|
||||
$this->hydraAdminBaseUrl.'/oauth2/auth/requests/logout',
|
||||
[
|
||||
'query' => [
|
||||
'logout_challenge' => $logoutChallenge,
|
||||
]
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
@ -56,27 +61,38 @@ class Client
|
||||
throw new InvalidChallengeException();
|
||||
}
|
||||
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function fetchConsentRequestInfo(string $consentChallenge): ResponseInterface
|
||||
{
|
||||
$response = $this->client->request(
|
||||
'GET',
|
||||
$this->hydraAdminBaseUrl . '/oauth2/auth/requests/consent',
|
||||
[
|
||||
'query' => [
|
||||
'consent_challenge' => $consentChallenge,
|
||||
$attempt = 0;
|
||||
while ($attempt < self::MAX_RETRY) {
|
||||
$response = $this->client->request(
|
||||
'GET',
|
||||
$this->hydraAdminBaseUrl.'/oauth2/auth/requests/consent',
|
||||
[
|
||||
'query' => [
|
||||
'consent_challenge' => $consentChallenge,
|
||||
],
|
||||
]
|
||||
]
|
||||
);
|
||||
);
|
||||
|
||||
switch ($response->getStatusCode()) {
|
||||
case 404:
|
||||
throw new InvalidChallengeException();
|
||||
$status = $response->getStatusCode();
|
||||
if (503 === $status) {
|
||||
++$attempt;
|
||||
usleep(1000 * self::SLEEP_TIME[$attempt] + rand(1, 5) * 1000);
|
||||
continue;
|
||||
}
|
||||
switch ($status) {
|
||||
case 404:
|
||||
throw new InvalidChallengeException();
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (self::MAX_RETRY === $attempt) {
|
||||
throw new Exception(sprintf('Fetch consent a rencontré une erreur %s après %s tentatives', $response->getStatusCode(), self::MAX_RETRY));
|
||||
}
|
||||
|
||||
|
||||
return $response;
|
||||
}
|
||||
@ -85,18 +101,18 @@ class Client
|
||||
{
|
||||
$response = $this->client->request(
|
||||
'PUT',
|
||||
$this->hydraAdminBaseUrl . '/oauth2/auth/requests/login/accept',
|
||||
$this->hydraAdminBaseUrl.'/oauth2/auth/requests/login/accept',
|
||||
[
|
||||
'query' => [
|
||||
'login_challenge' => $loginChallenge,
|
||||
],
|
||||
'headers' => [
|
||||
'Content-Type' => 'application/json'
|
||||
'Content-Type' => 'application/json',
|
||||
],
|
||||
'body' => json_encode($payload),
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
@ -104,13 +120,13 @@ class Client
|
||||
{
|
||||
$response = $this->client->request(
|
||||
'PUT',
|
||||
$this->hydraAdminBaseUrl . '/oauth2/auth/requests/consent/accept',
|
||||
$this->hydraAdminBaseUrl.'/oauth2/auth/requests/consent/accept',
|
||||
[
|
||||
'query' => [
|
||||
'consent_challenge' => $consentChallenge,
|
||||
],
|
||||
'headers' => [
|
||||
'Content-Type' => 'application/json'
|
||||
'Content-Type' => 'application/json',
|
||||
],
|
||||
'body' => json_encode($payload),
|
||||
]
|
||||
@ -123,13 +139,13 @@ class Client
|
||||
{
|
||||
$response = $this->client->request(
|
||||
'PUT',
|
||||
$this->hydraAdminBaseUrl . '/oauth2/auth/requests/logout/accept',
|
||||
$this->hydraAdminBaseUrl.'/oauth2/auth/requests/logout/accept',
|
||||
[
|
||||
'query' => [
|
||||
'logout_challenge' => $logoutChallenge,
|
||||
],
|
||||
'headers' => [
|
||||
'Content-Type' => 'application/json'
|
||||
'Content-Type' => 'application/json',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
@ -4,6 +4,6 @@ namespace App\SQLLogin\Exception;
|
||||
|
||||
use Exception;
|
||||
|
||||
class DatabaseConnectionException extends Exception
|
||||
class EmptyResultException extends Exception
|
||||
{
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\SQLLogin\Exception;
|
||||
|
||||
use Exception;
|
||||
|
||||
class InvalidSQLLoginAlgoException extends Exception
|
||||
{
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\SQLLogin\Exception;
|
||||
|
||||
use Exception;
|
||||
|
||||
class LoginElementsConfigurationException extends Exception
|
||||
{
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\SQLLogin\Exception;
|
||||
|
||||
use Exception;
|
||||
|
||||
class NullPasswordColumnNameException extends Exception
|
||||
{
|
||||
}
|
@ -24,12 +24,6 @@ class SQLLoginConnect extends AbstractController
|
||||
|
||||
public function connect($urlDatabase, $dbUser, $dbPassword): PDO
|
||||
{
|
||||
$options = [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_TIMEOUT => 5,
|
||||
PDO::ATTR_PERSISTENT => false,
|
||||
];
|
||||
|
||||
return new PDO($urlDatabase, $dbUser, $dbPassword, $options);
|
||||
return new PDO($urlDatabase, $dbUser, $dbPassword);
|
||||
}
|
||||
}
|
||||
|
@ -103,6 +103,6 @@ class SQLLoginRequest
|
||||
{
|
||||
$fields = join(',', array_merge($this->getPasswordFields(), $this->getDataFields()));
|
||||
|
||||
return 'SELECT '.$fields.' FROM '.$this->getTableName().' WHERE '.$this->getLoginColumnName().' = :'.$this->getLoginColumnName().';';
|
||||
return 'SELECT '.$fields.' FROM '.$this->getTableName().' WHERE LOWER('.$this->getLoginColumnName().') = LOWER(:'.$this->getLoginColumnName().');';
|
||||
}
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ class PasswordEncoder implements LegacyPasswordHasherInterface
|
||||
foreach ($this->securityPattern as $term) {
|
||||
if (self::PEPPER_PATTERN !== $term && self::PASSWORD_PATTERN !== $term && self::SALT_PATTERN !== $term) {
|
||||
$this->loggerInterface->critical('La configuration du security pattern est invalide, les termes autorisés sont : '.self::PASSWORD_PATTERN.', '.self::SALT_PATTERN.' et '.self::PEPPER_PATTERN);
|
||||
throw new SecurityPatternConfigurationException();
|
||||
throw new SecurityPatternConfigurationException('La configuration du security pattern est invalide, les termes autorisés sont : '.self::PASSWORD_PATTERN.', '.self::SALT_PATTERN.' et '.self::PEPPER_PATTERN);
|
||||
}
|
||||
}
|
||||
$completedPlainPassword = '';
|
||||
|
@ -5,13 +5,13 @@ namespace App\Security;
|
||||
use App\Entity\User;
|
||||
use App\Security\Hasher\PasswordEncoder;
|
||||
use App\Service\SQLLoginService;
|
||||
use App\SQLLogin\Exception\DatabaseConnectionException;
|
||||
use App\SQLLogin\Exception\DataToFetchConfigurationException;
|
||||
use App\SQLLogin\Exception\EmptyResultException;
|
||||
use App\SQLLogin\Exception\InvalidSQLPasswordException;
|
||||
use App\SQLLogin\Exception\LoginElementsConfigurationException;
|
||||
use App\SQLLogin\Exception\SecurityPatternConfigurationException;
|
||||
use App\SQLLogin\SQLLoginRequest;
|
||||
use Exception;
|
||||
use PDOException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
@ -26,27 +26,22 @@ class SQLLoginUserAuthenticator extends AbstractLoginFormAuthenticator
|
||||
{
|
||||
public const LOGIN_ROUTE = 'app_login';
|
||||
public const ERROR_LOGIN = 'error_login';
|
||||
public const ERROR_PDO = 'error_pdo';
|
||||
public const ERROR_SQL_LOGIN = 'error_sql_login';
|
||||
public const ERROR_CONFIGURATION = 'error_configuration';
|
||||
public const ERROR_DATA_TO_FETCH_CONFIGURATION = 'error_data_to_fetch_configuration';
|
||||
public const ERROR_SECURITY_PATTERN_CONFIGURATION = 'error_security_pattern_configuration';
|
||||
public const TECHNICAL_ERROR = 'technical_error';
|
||||
|
||||
private string $baseUrl;
|
||||
private SQLLoginService $sqlLoginService;
|
||||
private PasswordEncoder $passwordHasher;
|
||||
private SQLLoginRequest $sqlLoginRequest;
|
||||
|
||||
public function __construct(
|
||||
string $baseUrl,
|
||||
SQLLoginService $sqlLoginService,
|
||||
PasswordEncoder $passwordHasher,
|
||||
SQLLoginRequest $sqlLoginRequest
|
||||
private SQLLoginService $sqlLoginService,
|
||||
private PasswordEncoder $passwordHasher,
|
||||
private SQLLoginRequest $sqlLoginRequest,
|
||||
private LoggerInterface $logger
|
||||
) {
|
||||
$this->baseUrl = $baseUrl;
|
||||
$this->sqlLoginService = $sqlLoginService;
|
||||
$this->passwordHasher = $passwordHasher;
|
||||
$this->sqlLoginRequest = $sqlLoginRequest;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -61,14 +56,14 @@ class SQLLoginUserAuthenticator extends AbstractLoginFormAuthenticator
|
||||
|
||||
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey): RedirectResponse
|
||||
{
|
||||
return new RedirectResponse($this->baseUrl.'/connect/login-accept');
|
||||
return new RedirectResponse($this->baseUrl . '/connect/login-accept');
|
||||
}
|
||||
|
||||
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): RedirectResponse
|
||||
{
|
||||
$request->getSession()->set(Security::AUTHENTICATION_ERROR, $exception);
|
||||
|
||||
return new RedirectResponse($this->baseUrl.'/login');
|
||||
return new RedirectResponse($this->baseUrl . '/login');
|
||||
}
|
||||
|
||||
public function authenticate(Request $request): SelfValidatingPassport
|
||||
@ -80,60 +75,54 @@ class SQLLoginUserAuthenticator extends AbstractLoginFormAuthenticator
|
||||
$session = $request->getSession();
|
||||
try {
|
||||
$datas = $this->sqlLoginService->fetchPasswordAndDatas($login);
|
||||
$remoteHashedPassword = $datas[$this->sqlLoginRequest->getPasswordColumnName()];
|
||||
unset($datas[$this->sqlLoginRequest->getPasswordColumnName()]);
|
||||
$remoteSalt = $datas[$this->sqlLoginRequest->getSaltColumnName()];
|
||||
unset($datas[$this->sqlLoginRequest->getSaltColumnName()]);
|
||||
} catch (DatabaseConnectionException $e) {
|
||||
$session->set(self::ERROR_PDO, true);
|
||||
} catch (EmptyResultException $e) {
|
||||
$session->set(self::ERROR_LOGIN, true);
|
||||
$this->logger->warning("authentication failed", ['username' => $login, "remote_address" => $request->getClientIp()]);
|
||||
throw new AuthenticationException();
|
||||
} catch (LoginElementsConfigurationException $e) {
|
||||
$session->set(self::ERROR_CONFIGURATION, true);
|
||||
throw new AuthenticationException();
|
||||
} catch (DataToFetchConfigurationException $e) {
|
||||
$session->set(self::ERROR_DATA_TO_FETCH_CONFIGURATION, true);
|
||||
throw new AuthenticationException();
|
||||
} catch (Exception $exception) {
|
||||
$request->getSession()->set(self::ERROR_LOGIN, true);
|
||||
} catch (DataToFetchConfigurationException | PDOException $e) {
|
||||
\Sentry\captureException($e);
|
||||
$session->set(self::TECHNICAL_ERROR, true);
|
||||
throw new AuthenticationException();
|
||||
}
|
||||
|
||||
$remoteHashedPassword = $datas[$this->sqlLoginRequest->getPasswordColumnName()];
|
||||
unset($datas[$this->sqlLoginRequest->getPasswordColumnName()]);
|
||||
$remoteSalt = null;
|
||||
if ($this->sqlLoginRequest->getSaltColumnName() && isset($datas[$this->sqlLoginRequest->getSaltColumnName()])) {
|
||||
$remoteSalt = $datas[$this->sqlLoginRequest->getSaltColumnName()];
|
||||
unset($datas[$this->sqlLoginRequest->getSaltColumnName()]);
|
||||
}
|
||||
if (null === $remoteHashedPassword) {
|
||||
$remoteHashedPassword = '';
|
||||
}
|
||||
|
||||
try {
|
||||
// Comparaison remote hash et hash du input password + salt
|
||||
$this->passwordHasher->verify($remoteHashedPassword, $plaintextPassword, $remoteSalt);
|
||||
$user = new User($login, $remoteHashedPassword, $datas, $rememberMe);
|
||||
|
||||
$loader = function (string $userIdentifier) use ($user) {
|
||||
return $user->getLogin() == $userIdentifier ? $user : null;
|
||||
};
|
||||
$passport = new SelfValidatingPassport(new UserBadge($login, $loader));
|
||||
if ($rememberMe) {
|
||||
$passport->addBadge(new RememberMeBadge());
|
||||
}
|
||||
$passport->setAttribute('attributes', $user->getAttributes());
|
||||
|
||||
return $passport;
|
||||
} catch (InvalidSQLPasswordException $e) {
|
||||
$session->set(self::ERROR_LOGIN, true);
|
||||
throw new AuthenticationException();
|
||||
} catch (DataToFetchConfigurationException $e) {
|
||||
$session->set(self::ERROR_DATA_TO_FETCH_CONFIGURATION, true);
|
||||
throw new AuthenticationException();
|
||||
} catch (DatabaseConnectionException $e) {
|
||||
$session->set(self::ERROR_PDO, true);
|
||||
$this->logger->warning("authentication failed", ['username' => $login, "remote_address" => $request->getClientIp()]);
|
||||
throw new AuthenticationException();
|
||||
} catch (SecurityPatternConfigurationException $e) {
|
||||
$session->set(self::ERROR_SECURITY_PATTERN_CONFIGURATION, true);
|
||||
\Sentry\captureException($e);
|
||||
$session->set(self::TECHNICAL_ERROR, true);
|
||||
throw new AuthenticationException();
|
||||
}
|
||||
$user = new User($login, $remoteHashedPassword, $datas, $rememberMe);
|
||||
$loader = function (string $userIdentifier) use ($user) {
|
||||
return $user->getLogin() == $userIdentifier ? $user : null;
|
||||
};
|
||||
$passport = new SelfValidatingPassport(new UserBadge($login, $loader));
|
||||
if ($rememberMe) {
|
||||
$passport->addBadge(new RememberMeBadge());
|
||||
}
|
||||
$passport->setAttribute('attributes', $user->getAttributes());
|
||||
|
||||
$this->logger->warning("authentication succeeded", ['username' => $login, "remote_address" => $request->getClientIp()]);
|
||||
|
||||
return $passport;
|
||||
}
|
||||
|
||||
protected function getLoginUrl(Request $request): string
|
||||
{
|
||||
return $this->baseUrl.'/login';
|
||||
return $this->baseUrl . '/login';
|
||||
}
|
||||
}
|
||||
|
@ -2,20 +2,16 @@
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use App\SQLLogin\Exception\DatabaseConnectionException;
|
||||
use App\SQLLogin\Exception\DataToFetchConfigurationException;
|
||||
use App\SQLLogin\Exception\LoginElementsConfigurationException;
|
||||
use App\SQLLogin\Exception\NullDataToFetchException;
|
||||
use App\SQLLogin\Exception\EmptyResultException;
|
||||
use App\SQLLogin\SQLLoginConnect;
|
||||
use App\SQLLogin\SQLLoginRequest;
|
||||
use PDO;
|
||||
use PDOException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
|
||||
class SQLLoginService extends AbstractController
|
||||
{
|
||||
private PDO $pdo;
|
||||
public const MAX_RETRY = 3;
|
||||
|
||||
public function __construct(
|
||||
private SQLLoginRequest $sqlLoginRequest,
|
||||
@ -23,31 +19,35 @@ class SQLLoginService extends AbstractController
|
||||
) {
|
||||
$this->sqlLoginRequest = $sqlLoginRequest;
|
||||
$this->loggerInterface = $loggerInterface;
|
||||
$this->pdo = $this->getConnection();
|
||||
}
|
||||
|
||||
public function fetchPasswordAndDatas(string $login): array
|
||||
{
|
||||
try {
|
||||
$dataRequest = $this->sqlLoginRequest->getDatasRequest();
|
||||
$datas = $this->executeRequestWithLogin($dataRequest, $login);
|
||||
} catch (NullDataToFetchException $e) {
|
||||
throw new DataToFetchConfigurationException($e->getMessage());
|
||||
} catch (PDOException $e) {
|
||||
$this->loggerInterface->critical($e->getMessage());
|
||||
throw new LoginElementsConfigurationException($e->getMessage());
|
||||
}
|
||||
$dataRequest = $this->sqlLoginRequest->getDatasRequest();
|
||||
$datas = $this->executeRequestWithLogin($dataRequest, $login);
|
||||
|
||||
return $datas;
|
||||
}
|
||||
|
||||
private function executeRequestWithLogin(string $request, string $login): array
|
||||
{
|
||||
$query = $this->pdo->prepare($request);
|
||||
$query->bindParam($this->sqlLoginRequest->getLoginColumnName(), $login, PDO::PARAM_STR);
|
||||
$query->execute();
|
||||
$datas = $query->fetch(PDO::FETCH_ASSOC);
|
||||
$query->closeCursor();
|
||||
$attempt = 0;
|
||||
while ($attempt < self::MAX_RETRY) {
|
||||
$pdo = $this->getConnection();
|
||||
$query = $pdo->prepare($request);
|
||||
$query->execute([$this->sqlLoginRequest->getLoginColumnName() => $login]);
|
||||
$datas = $query->fetch(PDO::FETCH_ASSOC);
|
||||
$query->closeCursor();
|
||||
if (false === $datas) {
|
||||
usleep(3000);
|
||||
++$attempt;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (self::MAX_RETRY === $attempt) {
|
||||
throw new EmptyResultException();
|
||||
}
|
||||
|
||||
return $datas;
|
||||
}
|
||||
@ -55,13 +55,8 @@ class SQLLoginService extends AbstractController
|
||||
private function getConnection(): PDO
|
||||
{
|
||||
// Appel du singleton
|
||||
try {
|
||||
$sqlLogin = SQLLoginConnect::getInstance();
|
||||
$pdo = $sqlLogin->connect($this->sqlLoginRequest->getDatabaseDsn(), $this->sqlLoginRequest->getDbUser(), $this->sqlLoginRequest->getDbPassword());
|
||||
} catch (PDOException $e) {
|
||||
$this->loggerInterface->critical($e->getMessage());
|
||||
throw new DatabaseConnectionException($e->getMessage());
|
||||
}
|
||||
$sqlLogin = SQLLoginConnect::getInstance();
|
||||
$pdo = $sqlLogin->connect($this->sqlLoginRequest->getDatabaseDsn(), $this->sqlLoginRequest->getDbUser(), $this->sqlLoginRequest->getDbPassword());
|
||||
|
||||
return $pdo;
|
||||
}
|
||||
|
12
symfony.lock
12
symfony.lock
@ -114,6 +114,18 @@
|
||||
"config/packages/lock.yaml"
|
||||
]
|
||||
},
|
||||
"symfony/monolog-bundle": {
|
||||
"version": "3.10",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "3.7",
|
||||
"ref": "aff23899c4440dd995907613c1dd709b6f59503f"
|
||||
},
|
||||
"files": [
|
||||
"config/packages/monolog.yaml"
|
||||
]
|
||||
},
|
||||
"symfony/routing": {
|
||||
"version": "5.4",
|
||||
"recipe": {
|
||||
|
@ -9,25 +9,9 @@
|
||||
<source>error.login</source>
|
||||
<target>Incorrect login or password</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="36t19qm" resname="error.sql_login">
|
||||
<source>error.sql_login</source>
|
||||
<target>Connection to database encountered a problem</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="lBole_G" resname="error.pdo">
|
||||
<source>error.pdo</source>
|
||||
<target>Connection to database encountered a problem</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="1QRR4uA" resname="error.configuration">
|
||||
<source>error.configuration</source>
|
||||
<target>Identification data references do not exist in the database</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="4EPIhsV" resname="error.data_to_fetch_configuration">
|
||||
<source>error.data_to_fetch_configuration</source>
|
||||
<target>Data references to be transmitted do not exist</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="6iuTNs3" resname="error.security_pattern_configuration">
|
||||
<source>error.security_pattern_configuration</source>
|
||||
<target>The security pattern is not allowed</target>
|
||||
<trans-unit id="1QRR4uA" resname="error.technical">
|
||||
<source>error.technical</source>
|
||||
<target>A technical error happened, try again later</target>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
@ -9,25 +9,9 @@
|
||||
<source>error.login</source>
|
||||
<target>Login ou mot de passe inconnu</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="36t19qm" resname="error.sql_login">
|
||||
<source>error.sql_login</source>
|
||||
<target>La connexion à la base de données a rencontré un problème</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="lBole_G" resname="error.pdo">
|
||||
<source>error.pdo</source>
|
||||
<target>La connexion à la base de données a rencontré un problème</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="1QRR4uA" resname="error.configuration">
|
||||
<source>error.configuration</source>
|
||||
<target>Les références de données d'identification n'existent pas dans la base de données</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="4EPIhsV" resname="error.data_to_fetch_configuration">
|
||||
<source>error.data_to_fetch_configuration</source>
|
||||
<target>Les références de données à transmettre n'existent pas</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="6iuTNs3" resname="error.security_pattern_configuration">
|
||||
<source>error.security_pattern_configuration</source>
|
||||
<target>Le patron de sécurité n'est pas autorisé</target>
|
||||
<trans-unit id="1QRR4uA" resname="error.technical">
|
||||
<source>error.technical</source>
|
||||
<target>Une erreur technique s'est produite, rééssayez plus tard</target>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
Reference in New Issue
Block a user