Skip to content

Commit 742eaae

Browse files
authored
Merge pull request #1803 from OpenConext/feature/add-in-flight-authentications-limit
Add in flight authentication limit
2 parents 70079ee + a393220 commit 742eaae

File tree

20 files changed

+206
-50
lines changed

20 files changed

+206
-50
lines changed

app/config/parameters.yml.dist

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ parameters:
192192
## Settings for detecting whether the user is stuck in a authentication loop within his session
193193
time_frame_for_authentication_loop_in_seconds: 60
194194
maximum_authentication_procedures_allowed: 5
195+
maximum_authentications_per_session: 20
195196

196197
## Store attributes with their values, meaning that if an Idp suddenly
197198
## sends a new value (like a new e-mail address) consent has to be

ci/qa/behat.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ chown -R www-data app/cache/
2323
chmod -R 0777 /tmp/eb-fixtures
2424

2525
echo -e "\nRun the Behat tests\n"
26-
./vendor/bin/behat -c ./tests/behat-ci.yml --suite default -vv --format progress --strict
26+
./vendor/bin/behat -c ./tests/behat-ci.yml --suite default -vv --format progress --strict $@
2727

2828
#echo -e "\nBehat tests (with selenium and headless Chrome)\n"
2929
#./vendor/bin/behat -c ./tests/behat-ci.yml --suite selenium -vv --format progress --strict

ci/qa/phpcbf.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,6 @@ cd $(dirname $0)/../../
55

66
echo -e "\nPHP CodeSniffer\n"
77
./vendor/bin/phpcbf --standard=ci/qa-config/phpcs.xml src
8+
9+
echo -e "\nPHP CodeSniffer (legacy code)\n"
10+
./vendor/bin/phpcs --standard=ci/qa-config/phpcs-legacy.xml library

languages/messages.en.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,8 @@
222222
'error_stuck_in_authentication_loop_desc_no_idp_name' => 'You\'ve successfully authenticated at your %organisationNoun% but %spName% sends you back again to %suiteName%. Because you are already logged in, %suiteName% then sends you back to %spName%, which results in an infinite black hole. Likely, this is caused by an error at %spName%.',
223223
'error_stuck_in_authentication_loop_desc_no_sp_name' => 'You\'ve successfully authenticated at %idpName% but the service you are trying to access sends you back again to %suiteName%. Because you are already logged in, %suiteName% then sends you back to the service, which results in an infinite black hole. Likely, this is caused by an error at the Service Provider.',
224224
'error_stuck_in_authentication_loop_desc_no_name' => 'You\'ve successfully authenticated at your %organisationNoun% but the service you are trying to access sends you back again to %suiteName%. Because you are already logged in, %suiteName% then sends you back to the service, which results in an infinite black hole. Likely, this is caused by an error at the Service Provider.',
225+
'error_authentication_limit_exceeded' => 'Error - too many authentications in progress',
226+
'error_authentication_limit_exceeded_desc' => 'Too many authentications in progress',
225227
'error_no_authentication_request_received' => 'Error - No authentication request received.',
226228
'error_authn_context_class_ref_blacklisted' => 'Error - AuthnContextClassRef value is not allowed',
227229
'error_authn_context_class_ref_blacklisted_desc' => 'You cannot login because %idpName% sent a value for AuthnContextClassRef that is not allowed. Please contact the service desk of %idpName% to solve this.',

languages/messages.nl.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,8 @@
219219
'error_stuck_in_authentication_loop_desc_no_idp_name' => 'Je bent succesvol ingelogd bij je %organisationNoun% maar %spName% stuurt je weer terug naar %suiteName%. Omdat je succesvol bent ingelogd, stuurt %suiteName% je weer naar %spName%, wat resulteert in een oneindig zwart gat. Dit komt waarschijnlijk door een foutje aan de kant van %spName%.',
220220
'error_stuck_in_authentication_loop_desc_no_sp_name' => 'Je bent succesvol ingelogd bij %idpName% maar de dienst waar je naartoe wilt stuurt je weer terug naar %suiteName%. Omdat je succesvol bent ingelogd, stuurt %suiteName% je weer naar de dienst, wat resulteert in een oneindig zwart gat. Dit komt waarschijnlijk door een foutje aan de kant van de dienst.',
221221
'error_stuck_in_authentication_loop_desc_no_name' => 'Je bent succesvol ingelogd bij je %organisationNoun% maar de dienst waar je naartoe wilt stuurt je weer terug naar %suiteName%. Omdat je succesvol bent ingelogd, stuurt %suiteName% je weer naar de dienst, wat resulteert in een oneindig zwart gat. Dit komt waarschijnlijk door een foutje aan de kant van de dienst.',
222+
'error_authentication_limit_exceeded' => 'Fout - teveel onafgeronde authenticaties tegelijkertijd.',
223+
'error_authentication_limit_exceeded_desc' => 'Teveel onafgeronde authenticaties tegelijkertijd.',
222224
'error_no_authentication_request_received' => 'Fout - Geen authenticatie-aanvraag ontvangen.',
223225
'error_authn_context_class_ref_blacklisted' => 'Fout - Waarde van AuthnContextClassRef is niet toegestaan',
224226
'error_authn_context_class_ref_blacklisted_desc' => 'Je kunt niet inloggen omdat %idpName% een waarde stuurde voor AuthnContextClassRef die niet is toegestaan. Neem contact op met de helpdesk van %idpName% om dit op te lossen.',

languages/messages.pt.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,8 @@
216216
'error_stuck_in_authentication_loop_desc_no_idp_name' => 'Autenticou-se com sucesso no seu Fornecedor de Identidade, mas o %spName% reencaminhou-o de volta para %suiteName%. Como já está autenticado, o %suiteName% o reencaminha de volta para o %spName%, o que resulta num ciclo infinito. Muito provavelmente, isto é provocado por um erro no %spName%.',
217217
'error_stuck_in_authentication_loop_desc_no_sp_name' => 'Autenticou-se com sucesso no seu %idpName%, mas o serviço reencaminhou-o de volta para %suiteName%. Como já está autenticado, o %suiteName% o reencaminha de volta para o serviço, o que resulta num ciclo infinito. Muito provavelmente, isto é provocado por um erro no Fornecedor de Serviço.',
218218
'error_stuck_in_authentication_loop_desc_no_name' => 'Autenticou-se com sucesso no seu Fornecedor de Identidade, mas o serviço ao qual está a tentar aceder reencaminhou-o de volta para %suiteName%. Como já está autenticado, o %suiteName% o reencaminha de volta para o serviço, o que resulta num ciclo infinito. Muito provavelmente, isto é provocado por um erro no Fornecedor de Serviço.',
219+
'error_authentication_limit_exceeded' => 'Error - too many authentications in progress',
220+
'error_authentication_limit_exceeded_desc' => 'Too many authentications in progress',
219221
'error_authn_context_class_ref_blacklisted' => 'Erro - O valor para AuthnContextClassRef não é permitido',
220222
'error_authn_context_class_ref_blacklisted_desc' => '<p>Não pode autenticar-se porque a %idpName% enviou um valor para AuthnContextClassRef que não é permitido.</p>',
221223
'error_authn_context_class_ref_blacklisted_desc_no_idp_name' => '<p>Não pode autenticar-se porque a sua %organisationNoun% enviou um valor para AuthnContextClassRef que não é permitido.</p>',

src/OpenConext/EngineBlockBundle/Authentication/AuthenticationLoopGuard.php

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,15 @@ final class AuthenticationLoopGuard implements AuthenticationLoopGuardInterface
3434
*/
3535
private $timeFrameForAuthenticationLoopInSeconds;
3636

37+
/**
38+
* @var int
39+
*/
40+
private $maximumAuthenticationsPerSession;
41+
3742
public function __construct(
3843
$maximumAuthenticationProceduresAllowed,
39-
$timeFrameForAuthenticationLoopInSeconds
44+
$timeFrameForAuthenticationLoopInSeconds,
45+
$maximumAuthenticationsPerSession
4046
) {
4147
Assertion::integer(
4248
$maximumAuthenticationProceduresAllowed,
@@ -46,20 +52,20 @@ public function __construct(
4652
$timeFrameForAuthenticationLoopInSeconds,
4753
'Expected time frame for determining authentication loop in seconds to be an integer, got "%s"'
4854
);
55+
Assertion::integer(
56+
$maximumAuthenticationsPerSession,
57+
'Expected maximum authentication per session to be an integer, got "%s"'
58+
);
4959

5060
$this->maximumAuthenticationProceduresAllowed = $maximumAuthenticationProceduresAllowed;
5161
$this->timeFrameForAuthenticationLoopInSeconds = $timeFrameForAuthenticationLoopInSeconds;
62+
$this->maximumAuthenticationsPerSession = $maximumAuthenticationsPerSession;
5263
}
5364

54-
/**
55-
* @param Entity $serviceProvider
56-
* @param AuthenticationProcedureMap $pastAuthenticationProcedures
57-
* @return bool
58-
*/
5965
public function detectsAuthenticationLoop(
6066
Entity $serviceProvider,
6167
AuthenticationProcedureMap $pastAuthenticationProcedures
62-
) {
68+
): bool {
6369
$now = new DateTimeImmutable;
6470
$startDate = $now->modify(sprintf('-%d seconds', $this->timeFrameForAuthenticationLoopInSeconds));
6571

@@ -70,4 +76,18 @@ public function detectsAuthenticationLoop(
7076

7177
return $processedLoginProcedures >= $this->maximumAuthenticationProceduresAllowed;
7278
}
79+
80+
81+
/**
82+
* @param AuthenticationProcedureMap $pastAuthenticationProcedures
83+
* @return bool
84+
*/
85+
public function detectsAuthenticationLimit(
86+
AuthenticationProcedureMap $pastAuthenticationProcedures
87+
): bool {
88+
$processedLoginProcedures = $pastAuthenticationProcedures
89+
->count();
90+
91+
return $processedLoginProcedures >= $this->maximumAuthenticationsPerSession;
92+
}
7393
}

src/OpenConext/EngineBlockBundle/Authentication/AuthenticationLoopGuardInterface.php

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,12 @@
2222

2323
interface AuthenticationLoopGuardInterface
2424
{
25-
/**
26-
* @param Entity $serviceProvider
27-
* @param AuthenticationProcedureMap $pastAuthenticationProcedures
28-
* @return
29-
*/
3025
public function detectsAuthenticationLoop(
3126
Entity $serviceProvider,
3227
AuthenticationProcedureMap $pastAuthenticationProcedures
33-
);
28+
): bool;
29+
30+
public function detectsAuthenticationLimit(
31+
AuthenticationProcedureMap $pastAuthenticationProcedures
32+
): bool;
3433
}

src/OpenConext/EngineBlockBundle/Authentication/AuthenticationState.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use Assert\AssertionFailedException;
2222
use DateTimeImmutable;
2323
use OpenConext\EngineBlock\Assert\Assertion;
24+
use OpenConext\EngineBlockBundle\Exception\AuthenticationSessionLimitExceededException;
2425
use OpenConext\EngineBlockBundle\Exception\LogicException;
2526
use OpenConext\EngineBlockBundle\Exception\StuckInAuthenticationLoopException;
2627
use OpenConext\Value\Saml\Entity;
@@ -54,6 +55,23 @@ public function startAuthenticationOnBehalfOf(string $requestId, Entity $service
5455
Assertion::string($requestId, 'The requestId must be a string (XML ID) value');
5556
$currentAuthenticationProcedure = AuthenticationProcedure::onBehalfOf($serviceProvider);
5657

58+
// Validate if the processed authentications this session do not exceed the configured maximum of authentications
59+
$authenticationLimitExceeded = $this->authenticationLoopGuard->detectsAuthenticationLimit(
60+
$this->authenticationProcedures
61+
);
62+
63+
if ($authenticationLimitExceeded) {
64+
session_destroy();
65+
66+
throw new AuthenticationSessionLimitExceededException(
67+
'More than the configured maximum authentication procedures for this session'
68+
. ' the user seems to have started too much authentications this session. '
69+
. ' Resetting the session.'
70+
);
71+
}
72+
73+
// Validate if the processed authentications for the service provider for this session do not exceed
74+
// the configured maximum authentications in a configured time frame.
5775
$inAuthenticationLoop = $this->authenticationLoopGuard->detectsAuthenticationLoop(
5876
$serviceProvider,
5977
$this->authenticationProcedures

src/OpenConext/EngineBlockBundle/Controller/FeedbackController.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,14 @@ public function stuckInAuthenticationLoopAction()
454454
);
455455
}
456456

457+
public function authenticationLimitExceededAction()
458+
{
459+
return new Response(
460+
$this->twig->render('@theme/Authentication/View/Feedback/authentication-limit-exceeded.html.twig'),
461+
429
462+
);
463+
}
464+
457465
/**
458466
* @return Response
459467
*/

0 commit comments

Comments
 (0)