Verified Commit d2ae9f7c authored by Pavel Břoušek's avatar Pavel Břoušek
Browse files

fix: do not show no token page when MFA is only preferred

also fix getting entityID for excluded SPs
parent aea03a82
Loading
Loading
Loading
Loading
Loading
+27 −14
Original line number Diff line number Diff line
@@ -130,7 +130,9 @@ class SwitchAuth extends \SimpleSAML\Auth\ProcessingFilter
    {
        $this->getConfig($this->config);

        $mfaEnforced = Utils::isMFAEnforced($state, $this->entityID);
        $rpIdentifier = self::getEntityID($this->entityID, $state);

        $mfaEnforced = Utils::isMFAEnforced($state, $rpIdentifier);

        $usersCapabilities = $this->getMFAForUid($state);

@@ -154,13 +156,10 @@ class SwitchAuth extends \SimpleSAML\Auth\ProcessingFilter

        self::info('supported requested contexts: ' . json_encode($this->supported_requested_contexts));

        $shouldPerformMFA = !$this->authnContextHelper->MFAin([
                $upstreamContext,
            ]) && (
                $mfaEnforced
                || empty($this->supported_requested_contexts)
                || $this->authnContextHelper->isMFAprefered($this->supported_requested_contexts)
            );
        $mustPerformMFA = $this->authnContextHelper->MFAin([$upstreamContext]) ? false
            : ($mfaEnforced || empty($this->supported_requested_contexts));
        $shouldPerformMFA = $this->authnContextHelper->MFAin([$upstreamContext]) ? false
            : ($mustPerformMFA || $this->authnContextHelper->isMFAprefered($this->supported_requested_contexts));

        if (
            $this->mfa_preferred_privacyidea_fail
@@ -171,10 +170,10 @@ class SwitchAuth extends \SimpleSAML\Auth\ProcessingFilter
        }

        if (
            $shouldPerformMFA
            $mustPerformMFA
            && empty($state['Attributes'][AuthSwitcher::MFA_TOKENS])
            && !empty($this->setup_mfa_redirect_url)
            && !in_array($this->entityID, $this->mfa_excluded_sps)
            && !in_array($rpIdentifier, $this->mfa_excluded_sps)
        ) {
            self::info('user must perform MFA but has no tokens, redirect to setup');
            $url = Module::getModuleURL(self::SETUP_MFA_URL);
@@ -184,10 +183,8 @@ class SwitchAuth extends \SimpleSAML\Auth\ProcessingFilter
            exit;
        }
        if (empty($this->supported_requested_contexts)) {
            Logger::info(
                'authswitcher: no requested AuthnContext can be fulfilled: ' . json_encode($requestedContexts)
            );
            self::noAuthnContextResponder($state);
            Logger::info('authswitcher: no requested AuthnContext can be fulfilled');
            AuthnContextHelper::noAuthnContextResponder($state);
        }

        // switch to MFA if enforced or preferred but not already done if we handle the proxy mode
@@ -406,4 +403,20 @@ class SwitchAuth extends \SimpleSAML\Auth\ProcessingFilter
        $state['Attributes']['MFA_FILTER_INDEX'] = array_search($filter, $state['Attributes']['MFA_FILTERS'], true);
        Utils::runAuthProcFilter($filter, $this->configs[$filter], $state, $this->reserved);
    }

    private static function getEntityID($entityID, $request)
    {
        if ($entityID === null) {
            return $request['SPMetadata']['entityid'];
        }
        if (is_callable($entityID)) {
            return call_user_func($entityID, $request);
        }
        if (!is_string($entityID)) {
            throw new Exception(
                self::DEBUG_PREFIX . 'Invalid configuration option entityID. It must be a string or a callable.'
            );
        }
        return $entityID;
    }
}
+1 −3
Original line number Diff line number Diff line
@@ -79,8 +79,7 @@ class AuthnContextHelper
            $usersCapabilities,
            $supportedRequestedContexts,
            $state['saml:RequestedAuthnContext']['Comparison'] ?? Constants::COMPARISON_EXACT,
            $upstreamContext,
            $mfaEnforced
            $upstreamContext
        );
        if ($requestResult === null) {
            Logger::info('authswitcher: comparsion type maxium is not supported');
@@ -133,7 +132,6 @@ class AuthnContextHelper
     * @param mixed      $supportedRequestedContexts
     * @param mixed      $comparison
     * @param mixed|null $upstreamContext
     * @param mixed      $mfaEnforced
     */
    private function testComparison(
        $usersCapabilities,
+1 −19
Original line number Diff line number Diff line
@@ -55,7 +55,7 @@ class Utils
        }
    }

    public static function isMFAEnforced($state, $entityID = null)
    public static function isMFAEnforced($state, $rpIdentifier)
    {
        if (!empty($state['Attributes'][AuthSwitcher::MFA_ENFORCE_SETTINGS])) {
            $settings = $state['Attributes'][AuthSwitcher::MFA_ENFORCE_SETTINGS];
@@ -73,8 +73,6 @@ class Utils

            $rpCategory = $state['Attributes'][AuthSwitcher::RP_CATEGORY][0] ?? 'other';

            $rpIdentifier = self::getEntityID($entityID, $state);

            if (
                !empty($settings['include_categories']) && in_array(
                    $rpCategory,
@@ -92,20 +90,4 @@ class Utils
        Logger::info(self::DEBUG_PREFIX . 'MFA was not forced');
        return false;
    }

    private static function getEntityID($entityID, $request)
    {
        if ($entityID === null) {
            return $request['SPMetadata']['entityid'];
        }
        if (is_callable($entityID)) {
            return call_user_func($entityID, $request);
        }
        if (!is_string($entityID)) {
            throw new Exception(
                self::DEBUG_PREFIX . 'Invalid configuration option entityID. It must be a string or a callable.'
            );
        }
        return $entityID;
    }
}