/**
 * Processes an authentication request from a relying party.
 *
 * An authentication request has an openid.mode value of
 * checkid_setup or checkid_immediate.
 *
 * If the authentication request is a standard OpenID request about an identity
 * (i.e. contains the key openid.identity), this function calls
 * {@link simpleid_checkid_identity()} to see whether the user logged on into SimpleID
 * matches the identity supplied in the OpenID request.
 *
 * If the authentication request is not about an identity, this function calls
 * the {@link hook_checkid() checkid hook} of the loaded extensions.
 *
 * Depending on the OpenID version, this function will supply an appropriate
 * assertion.
 *
 * @param array $request the OpenID request
 *
 */
function simpleid_checkid($request)
{
    global $version;
    $immediate = $request['openid.mode'] == 'checkid_immediate';
    log_info('OpenID authentication request: ' . ($immediate ? 'immediate' : 'setup') . '; ' . log_array($request));
    // Check for protocol correctness
    if ($version == OPENID_VERSION_1_1) {
        if (!isset($request['openid.return_to'])) {
            log_error('Protocol Error: openid.return_to not set.');
            indirect_fatal_error('Protocol Error: openid.return_to not set.');
            return;
        }
        if (!isset($request['openid.identity'])) {
            log_error('Protocol Error: openid.identity not set.');
            indirect_fatal_error('Protocol Error: openid.identity not set.');
            return;
        }
    }
    if ($version >= OPENID_VERSION_2) {
        if (isset($request['openid.identity']) && !isset($request['openid.claimed_id'])) {
            log_error('Protocol Error: openid.identity set, but not openid.claimed_id.');
            indirect_fatal_error('Protocol Error: openid.identity set, but not openid.claimed_id.');
            return;
        }
        if (!isset($request['openid.realm']) && !isset($request['openid.return_to'])) {
            log_error('Protocol Error: openid.return_to not set when openid.realm is not set.');
            indirect_fatal_error('Protocol Error: openid.return_to not set when openid.realm is not set.');
            return;
        }
    }
    if (isset($request['openid.return_to'])) {
        $realm = openid_get_realm($request, $version);
        if (!openid_url_matches_realm($request['openid.return_to'], $realm)) {
            log_error('Protocol Error: openid.return_to does not match realm.');
            openid_indirect_error($request['openid.return_to'], 'Protocol Error: openid.return_to does not match realm.');
            return;
        }
    }
    if (isset($request['openid.identity'])) {
        // Standard request
        log_debug('openid.identity found, use simpleid_checkid_identity');
        $result = simpleid_checkid_identity($request, $immediate);
    } else {
        log_debug('openid.identity not found, trying extensions');
        // Extension request
        $results = extension_invoke_all('checkid', $request, $immediate);
        // Filter out nulls
        $results = array_merge(array_diff($results, array(NULL)));
        // If there are still results, it is the lowest value, otherwise, it is CHECKID_PROTOCOL_ERROR
        $result = $results ? min($results) : CHECKID_PROTOCOL_ERROR;
    }
    switch ($result) {
        case CHECKID_APPROVAL_REQUIRED:
            log_info('CHECKID_APPROVAL_REQUIRED');
            if ($immediate) {
                $response = simpleid_checkid_approval_required($request);
                simpleid_assertion_response($response, $request['openid.return_to']);
            } else {
                $response = simpleid_checkid_ok($request);
                simpleid_openid_consent_form($request, $response, $result);
            }
            break;
        case CHECKID_RETURN_TO_SUSPECT:
            log_info('CHECKID_RETURN_TO_SUSPECT');
            if ($immediate) {
                $response = simpleid_checkid_error($request, $immediate);
                simpleid_assertion_response($response, $request['openid.return_to']);
            } else {
                $response = simpleid_checkid_ok($request);
                simpleid_openid_consent_form($request, $response, $result);
            }
            break;
        case CHECKID_OK:
            log_info('CHECKID_OK');
            $response = simpleid_checkid_ok($request);
            $response = simpleid_sign($response, isset($request['openid.assoc_handle']) ? $request['openid.assoc_handle'] : NULL);
            simpleid_assertion_response($response, $request['openid.return_to']);
            break;
        case CHECKID_LOGIN_REQUIRED:
            log_info('CHECKID_LOGIN_REQUIRED');
            if ($immediate) {
                $response = simpleid_checkid_login_required($request);
                simpleid_assertion_response($response, $request['openid.return_to']);
            } else {
                user_login_form('continue', pickle($request));
                exit;
            }
            break;
        case CHECKID_IDENTITIES_NOT_MATCHING:
        case CHECKID_IDENTITY_NOT_EXIST:
            log_info('CHECKID_IDENTITIES_NOT_MATCHING | CHECKID_IDENTITY_NOT_EXIST');
            $response = simpleid_checkid_error($request, $immediate);
            if ($immediate) {
                simpleid_assertion_response($response, $request['openid.return_to']);
            } else {
                simpleid_openid_consent_form($request, $response, $result);
            }
            break;
        case CHECKID_PROTOCOL_ERROR:
            if (isset($request['openid.return_to'])) {
                $response = simpleid_checkid_error($request, $immediate);
                simpleid_assertion_response($response, $request['openid.return_to']);
            } else {
                indirect_fatal_error('Unrecognised request.');
            }
            break;
    }
}
/**
 * Entry point for SimpleID upgrade script.
 *
 * @see user_init()
 */
function upgrade_start()
{
    global $xtpl, $GETPOST;
    $xtpl = new XTemplate('html/template.xtpl');
    $xtpl->assign('version', SIMPLEID_VERSION);
    $xtpl->assign('base_path', get_base_path());
    $xtpl->assign('css', '@import url(' . get_base_path() . 'html/upgrade.css);');
    // Check if the configuration file has been defined
    if (!defined('SIMPLEID_BASE_URL')) {
        indirect_fatal_error('No configuration file found.  See the <a href="http://simpleid.koinic.net/documentation/getting-started">manual</a> for instructions on how to set up a configuration file.');
    }
    if (!is_dir(SIMPLEID_IDENTITIES_DIR)) {
        indirect_fatal_error('Identities directory not found.  See the <a href="http://simpleid.koinic.net/documentation/getting-started">manual</a> for instructions on how to set up SimpleID.');
    }
    if (!is_dir(SIMPLEID_CACHE_DIR) || !is_writeable(SIMPLEID_CACHE_DIR)) {
        indirect_fatal_error('Cache directory not found or not writeable.  See the <a href="http://simpleid.koinic.net/documentation/getting-started">manual</a> for instructions on how to set up SimpleID.');
    }
    if (!is_dir(SIMPLEID_STORE_DIR) || !is_writeable(SIMPLEID_STORE_DIR)) {
        indirect_fatal_error('Store directory not found or not writeable.  See the <a href="http://simpleid.koinic.net/documentation/getting-started">manual</a> for instructions on how to set up SimpleID.');
    }
    if (@ini_get('register_globals') === 1 || @ini_get('register_globals') === '1' || strtolower(@ini_get('register_globals')) == 'on') {
        indirect_fatal_error('register_globals is enabled in PHP configuration, which is not supported by SimpleID.  See the <a href="http://simpleid.koinic.net/documentation/getting-started/system-requirements">manual</a> for further information.');
    }
    if (!bignum_loaded()) {
        log_fatal('gmp/bcmath PHP extension not loaded.');
        indirect_fatal_error('One or more required PHP extensions (gmp/bcmath) is not loaded.  See the <a href="http://simpleid.koinic.net/documentation/getting-started/system-requirements">manual</a> for further information on system requirements.');
    }
    if (!function_exists('preg_match')) {
        log_fatal('pcre PHP extension not loaded.');
        indirect_fatal_error('One or more required PHP extensions (pcre) is not loaded.  See the <a href="http://simpleid.koinic.net/documentation/getting-started/system-requirements">manual</a> for further information on system requirements.');
    }
    if (!function_exists('session_start')) {
        log_fatal('session PHP extension not loaded.');
        indirect_fatal_error('One or more required PHP extensions (session) is not loaded.  See the <a href="http://simpleid.koinic.net/documentation/getting-started/system-requirements">manual</a> for further information on system requirements.');
    }
    if (@ini_get('suhosin.get.max_value_length') !== false && @ini_get('suhosin.get.max_value_length') < 1024) {
        log_fatal('suhosin.get.max_value_length < 1024');
        indirect_fatal_error('suhosin.get.max_value_length is less than 1024, which will lead to problems. See the <a href="http://simpleid.koinic.net/documentation/getting-started/system-requirements">manual</a> for further information on system requirements.');
    }
    $q = isset($GETPOST['q']) ? $GETPOST['q'] : '';
    $q = explode('/', $q);
    extension_init();
    user_init(NULL);
    upgrade_user_init();
    $routes = array('upgrade-selection' => 'upgrade_selection', 'upgrade-apply' => 'upgrade_apply', '.*' => 'upgrade_info');
    simpleweb_run($routes, implode('/', $q));
}