17
17
use SimpleSAML \Module ;
18
18
use SimpleSAML \Module \mfa \LoggerFactory ;
19
19
use SimpleSAML \Utils \HTTP ;
20
+ use Throwable ;
20
21
21
22
/**
22
23
* Filter which prompts the user for MFA credentials.
25
26
*/
26
27
class Mfa extends ProcessingFilter
27
28
{
28
- const SESSION_TYPE = 'mfa ' ;
29
29
const STAGE_SENT_TO_LOW_ON_BACKUP_CODES_NAG = 'mfa:sent_to_low_on_backup_codes_nag ' ;
30
- const STAGE_SENT_TO_MFA_CHANGE_URL = 'mfa:sent_to_mfa_change_url ' ;
31
30
const STAGE_SENT_TO_MFA_NEEDED_MESSAGE = 'mfa:sent_to_mfa_needed_message ' ;
32
31
const STAGE_SENT_TO_MFA_PROMPT = 'mfa:sent_to_mfa_prompt ' ;
33
32
const STAGE_SENT_TO_NEW_BACKUP_CODES_PAGE = 'mfa:sent_to_new_backup_codes_page ' ;
@@ -79,6 +78,9 @@ public function __construct(array $config, mixed $reserved)
79
78
$ this ->idBrokerClientClass = $ config ['idBrokerClientClass ' ] ?? IdBrokerClient::class;
80
79
}
81
80
81
+ /**
82
+ * @throws Exception
83
+ */
82
84
protected function loadValuesFromConfig (array $ config , array $ attributes ): void
83
85
{
84
86
foreach ($ attributes as $ attribute ) {
@@ -159,7 +161,7 @@ protected function getAttributeAllValues(string $attributeName, array $state): ?
159
161
* Get an ID Broker client.
160
162
*
161
163
* @param array $idBrokerConfig
162
- * @return IdBrokerClient
164
+ * @return IdBrokerClient|FakeIdBrokerClient
163
165
*/
164
166
private static function getIdBrokerClient (array $ idBrokerConfig ): IdBrokerClient |FakeIdBrokerClient
165
167
{
@@ -194,7 +196,7 @@ public static function getMfaOptionById(array $mfaOptions, int $mfaId): array
194
196
}
195
197
196
198
foreach ($ mfaOptions as $ mfaOption ) {
197
- if ((int )$ mfaOption ['id ' ] === ( int ) $ mfaId ) {
199
+ if ((int )$ mfaOption ['id ' ] === $ mfaId ) {
198
200
return $ mfaOption ;
199
201
}
200
202
}
@@ -310,16 +312,16 @@ public static function getTemplateFor(string $mfaType): string
310
312
* @param array $state
311
313
* @return string
312
314
*/
313
- protected static function getRelayStateUrl ($ state )
315
+ protected static function getRelayStateUrl (array $ state ): string
314
316
{
315
317
if (array_key_exists ('saml:RelayState ' , $ state )) {
316
318
$ samlRelayState = $ state ['saml:RelayState ' ];
317
319
318
- if (strpos ($ samlRelayState , "http:// " ) === 0 ) {
320
+ if (str_starts_with ($ samlRelayState , "http:// " )) {
319
321
return $ samlRelayState ;
320
322
}
321
323
322
- if (strpos ($ samlRelayState , "https:// " ) === 0 ) {
324
+ if (str_starts_with ($ samlRelayState , "https:// " )) {
323
325
return $ samlRelayState ;
324
326
}
325
327
}
@@ -349,7 +351,7 @@ public static function giveUserNewBackupCodes(array &$state, LoggerInterface $lo
349
351
'event ' => 'New backup codes result: succeeded ' ,
350
352
'employeeId ' => $ state ['employeeId ' ],
351
353
]));
352
- } catch (\ Throwable $ t ) {
354
+ } catch (Throwable $ t ) {
353
355
$ logger ->error (json_encode ([
354
356
'event ' => 'New backup codes result: failed ' ,
355
357
'employeeId ' => $ state ['employeeId ' ],
@@ -383,7 +385,7 @@ public static function hasMfaOptionsOtherThan(string $excludedMfaType, array $st
383
385
{
384
386
$ mfaOptions = $ state ['mfaOptions ' ] ?? [];
385
387
foreach ($ mfaOptions as $ mfaOption ) {
386
- if (strval ($ mfaOption ['type ' ]) !== strval ( $ excludedMfaType) ) {
388
+ if (strval ($ mfaOption ['type ' ]) !== $ excludedMfaType ) {
387
389
return true ;
388
390
}
389
391
}
@@ -398,12 +400,12 @@ protected function initComposerAutoloader(): void
398
400
}
399
401
}
400
402
401
- protected static function isHeadedToMfaSetupUrl ($ state , $ mfaSetupUrl )
403
+ protected static function isHeadedToMfaSetupUrl ($ state , $ mfaSetupUrl ): bool
402
404
{
403
405
if (array_key_exists ('saml:RelayState ' , $ state )) {
404
406
$ currentDestination = self ::getRelayStateUrl ($ state );
405
407
if (!empty ($ currentDestination )) {
406
- return (strpos ($ currentDestination , $ mfaSetupUrl ) === 0 );
408
+ return (str_starts_with ($ currentDestination , $ mfaSetupUrl ));
407
409
}
408
410
}
409
411
return false ;
@@ -416,15 +418,16 @@ protected static function isHeadedToMfaSetupUrl($state, $mfaSetupUrl)
416
418
*
417
419
* @param int $mfaId The ID of the MFA option used.
418
420
* @param string $employeeId The Employee ID that this MFA option belongs to.
419
- * @param string $mfaSubmission The value of the MFA submission.
421
+ * @param string|array $mfaSubmission The value of the MFA submission.
420
422
* @param array $state The array of state information.
421
423
* @param bool $rememberMe Whether or not to set remember me cookies
422
424
* @param LoggerInterface $logger A PSR-3 compatible logger.
423
425
* @param string $mfaType The type of the MFA ('webauthn', 'totp', 'backupcode').
424
426
* @param string $rpOrigin The Relying Party Origin (for WebAuthn)
425
427
* @return string If validation fails, an error message to show to the
426
428
* end user will be returned.
427
- * @throws \Sil\PhpEnv\EnvVarNotFoundException
429
+ * @throws EnvVarNotFoundException
430
+ * @throws Exception
428
431
*/
429
432
public static function validateMfaSubmission (
430
433
int $ mfaId ,
@@ -458,7 +461,7 @@ public static function validateMfaSubmission(
458
461
if ($ mfaDataFromBroker === true || count ($ mfaDataFromBroker ) > 0 ) {
459
462
$ idBrokerClient ->updateUserLastLogin ($ employeeId );
460
463
}
461
- } catch (\ Throwable $ t ) {
464
+ } catch (Throwable $ t ) {
462
465
$ message = 'Something went wrong while we were trying to do the '
463
466
. '2-step verification. ' ;
464
467
if ($ t instanceof ServiceException) {
@@ -539,7 +542,7 @@ public static function validateMfaSubmission(
539
542
*
540
543
* @param array $state
541
544
*/
542
- public static function redirectToMfaSetup (array & $ state ): void
545
+ public static function redirectToMfaSetup (array $ state ): void
543
546
{
544
547
$ mfaSetupUrl = $ state ['mfaSetupUrl ' ];
545
548
@@ -566,6 +569,7 @@ public static function redirectToMfaSetup(array &$state): void
566
569
567
570
/**
568
571
* @inheritDoc
572
+ * @throws Exception
569
573
*/
570
574
public function process (array &$ state ): void
571
575
{
@@ -686,7 +690,7 @@ protected function redirectToMfaPrompt(array &$state, string $employeeId, array
686
690
* @param array $mfaOptions
687
691
* @param array $state
688
692
* @return bool
689
- * @throws EnvVarNotFoundException
693
+ * @throws EnvVarNotFoundException|ServiceException
690
694
*/
691
695
public static function isRememberMeCookieValid (
692
696
string $ cookieHash ,
@@ -700,7 +704,7 @@ public static function isRememberMeCookieValid(
700
704
if ((int )$ expireDate > time ()) {
701
705
$ expectedString = self ::generateRememberMeCookieString ($ rememberSecret , $ state ['employeeId ' ], $ expireDate , $ mfaOptions );
702
706
$ isValid = password_verify ($ expectedString , $ cookieHash );
703
-
707
+
704
708
if ($ isValid ) {
705
709
$ idBrokerClient = self ::getIdBrokerClient ($ state ['idBrokerConfig ' ]);
706
710
$ idBrokerClient ->updateUserLastLogin ($ state ['employeeId ' ]);
@@ -734,8 +738,7 @@ public static function generateRememberMeCookieString(
734
738
}
735
739
}
736
740
737
- $ string = $ rememberSecret . $ employeeId . $ expireDate . $ allMfaIds ;
738
- return $ string ;
741
+ return $ rememberSecret . $ employeeId . $ expireDate . $ allMfaIds ;
739
742
}
740
743
741
744
/**
@@ -789,7 +792,7 @@ protected static function redirectToOutOfBackupCodesMessage(array &$state, strin
789
792
* @param string $employeeId
790
793
* @param array $mfaOptions
791
794
* @param string $rememberDuration
792
- * @throws \Sil\PhpEnv\ EnvVarNotFoundException
795
+ * @throws EnvVarNotFoundException
793
796
*/
794
797
public static function setRememberMeCookies (
795
798
string $ employeeId ,
@@ -818,8 +821,9 @@ protected static function shouldPromptForMfa(array $mfa): bool
818
821
*
819
822
* @param array $state The state data.
820
823
* @param LoggerInterface $logger A PSR-3 compatible logger.
824
+ * @throws Exception
821
825
*/
822
- public static function sendManagerCode (array &$ state , LoggerInterface $ logger ): string
826
+ public static function sendManagerCode (array &$ state , LoggerInterface $ logger ): void
823
827
{
824
828
try {
825
829
$ idBrokerClient = self ::getIdBrokerClient ($ state ['idBrokerConfig ' ]);
@@ -830,13 +834,14 @@ public static function sendManagerCode(array &$state, LoggerInterface $logger):
830
834
'event ' => 'Manager rescue code sent ' ,
831
835
'employeeId ' => $ state ['employeeId ' ],
832
836
]));
833
- } catch (\ Throwable $ t ) {
837
+ } catch (Throwable $ t ) {
834
838
$ logger ->error (json_encode ([
835
839
'event ' => 'Manager rescue code: failed ' ,
836
840
'employeeId ' => $ state ['employeeId ' ],
837
841
'error ' => $ t ->getCode () . ': ' . $ t ->getMessage (),
838
842
]));
839
- return 'There was an unexpected error. Please try again or contact tech support for assistance ' ;
843
+ throw new Exception ('There was an unexpected error. Please try again ' .
844
+ 'or contact tech support for assistance ' );
840
845
}
841
846
842
847
$ mfaOptions = $ state ['mfaOptions ' ];
@@ -932,7 +937,7 @@ protected static function updateStateWithNewMfaData(array &$state, LoggerInterfa
932
937
933
938
try {
934
939
$ newMfaOptions = $ idBrokerClient ->mfaList ($ state ['employeeId ' ]);
935
- } catch (Exception $ e ) {
940
+ } catch (Exception ) {
936
941
$ log ['status ' ] = 'failed: id-broker exception ' ;
937
942
$ logger ->error (json_encode ($ log ));
938
943
return ;
0 commit comments