@@ -886,6 +886,30 @@ public function reauthenticate(array &$state): void
886886 $ response = self ::askForIdPChange ($ state );
887887 $ response ->send ();
888888 }
889+
890+ /*
891+ * When proxying AuthnContextClassRef, we also need to check if the
892+ * original IdP used a compatible AuthnContext. If not, we may need
893+ * need to do step-up authentication (e.g. for requesting MFA). At
894+ * the moment this only handles exact comparisons, since handling
895+ * better/minimum/maximum would require a prioritised list.
896+ */
897+ if (
898+ $ this ->passAuthnContextClassRef
899+ && isset ($ state ['saml:RequestedAuthnContext ' ])
900+ && $ state ['saml:RequestedAuthnContext ' ]['Comparison ' ] === Constants::COMPARISON_EXACT
901+ && isset ($ data ['saml:sp:AuthnContext ' ])
902+ && $ state ['saml:RequestedAuthnContext ' ]['AuthnContextClassRef ' ][0 ] !== $ data ['saml:sp:AuthnContext ' ]
903+ ) {
904+ Logger::warning (sprintf (
905+ "Reauthentication requires change in AuthnContext from '%s' to '%s'. " ,
906+ $ data ['saml:sp:AuthnContext ' ],
907+ $ state ['saml:RequestedAuthnContext ' ]['AuthnContextClassRef ' ][0 ]
908+ ));
909+ $ state ['saml:idp ' ] = $ data ['saml:sp:IdP ' ];
910+ $ state ['saml:sp:AuthId ' ] = $ this ->authId ;
911+ self ::tryStepUpAuth ($ state );
912+ }
889913 }
890914
891915
@@ -931,6 +955,37 @@ public static function askForIdPChange(array &$state): RedirectResponse
931955 }
932956
933957
958+ /**
959+ * Attempt to re-authenticate using the same identity provider, perhaps
960+ * with different requirements (e.g. AuthnContext). Note that this method
961+ * is intended for instances of SimpleSAMLphp running as a SAML proxy,
962+ * and therefore acting as both an SP and an IdP at the same time.
963+ *
964+ * @param array The state array
965+ * The following keys must be defined:
966+ * - 'saml:idp': the IdP to re-authenticate with
967+ * - 'saml:sp:AuthId': the identifier of the current authentication source.
968+ * @throws \SAML2\Exception\Protocol\NoPassiveException In case the authentication request was passive.
969+ */
970+ public static function tryStepUpAuth (array &$ state ): void
971+ {
972+ Assert::keyExists ($ state , 'saml:idp ' );
973+ Assert::keyExists ($ state , 'saml:sp:AuthId ' );
974+
975+ if (isset ($ state ['isPassive ' ]) && (bool ) $ state ['isPassive ' ]) {
976+ // passive request, we cannot authenticate the user
977+ throw new NoPassiveException (
978+ Constants::STATUS_REQUESTER . ': Reauthentication required '
979+ );
980+ }
981+
982+ /** @var \SimpleSAML\Module\saml\Auth\Source\SP $as */
983+ $ as = new Auth \Simple ($ state ['saml:sp:AuthId ' ]);
984+ $ as ->login ($ state );
985+ Assert::true (false );
986+ }
987+
988+
934989 /**
935990 * Log the user out before logging in again.
936991 *
0 commit comments