<?php

#require dirname(__DIR__).'/php/OpenID-Connect-PHP-master/vendor/autoload.php';
require dirname(__DIR__).'/vendor/autoload.php';
use Jumbojett\OpenIDConnectClient;

require_once __DIR__.'/authenticator.abstract.class.php';

/**
 * Authentification des utilisateurs via un service OpenID Connect (OAuth).
 */
class authenticator_openid extends authenticator {

    /**
     * URL de redirection à fournir au provider pour qu'il puisse renvoyer les utilisateurs
     * vers openADS après qu'ils se soient authentifiés.
     */
    public string $redirect_url;

    /**
     * URL du provider OpenID Connect vers lequel openADS va rediriger les utilisateurs
     * afin qu'ils s'authentifient auprès de lui.
     */
    public string $provider_url;

    /**
     * Identifiant de l'application utilisé pour authentifier openADS auprès du provider
     * OpenID Connect.
     */
    public string $application_id;

    /**
     * Secret de l'application utilisé pour authentifier openADS auprès du provider
     * OpenID Connect.
     */
    protected string $application_secret;

    /**
     * Nom d'un attribut côté OpenID à utiliser pour effectuer la correspondance avec le
     * login côté openADS afin de savoir quel utilisateur vient de s'authentifier.
     */
    public string $user_attribute_for_login = 'login';

    /**
     * Injection de la dépendance au framework.
     *
     * @param application $framework  Instance du framework
     *
     * @return authenticator
     */
    public function __construct(application $framework) {
        $config_filename = 'openid.inc.php';
        $confilg_path = dirname(__DIR__)."/dyn/$config_filename";
        if (! is_file($confilg_path)) {
            throw new RuntimeException("Configuration OpenID Connect '$confilg_path' inexistante.");
        }
        $config = include $confilg_path;
        if (is_array($config)) {
            foreach(array(
                'redirect_url', 'provider_url', 'application_id', 'application_secret',
                'user_attribute_for_login'
            ) as $key) {
                if (! isset($config[$key]) || empty($config[$key])) {
                    throw new RuntimeException(
                        "Configuration OpenID Connect invalide (manque la clé '$key')");
                }
                $this->$key = $config[$key];
            }
        }

        /*$no_session = session_status() === PHP_SESSION_NONE;
        $framework->log(__METHOD__, "no session: ".var_export($no_session, true), 'DEBUG', 'auth');
        if (! $no_session) {
            $session_name = session_name();
            $framework->log(__METHOD__, "session name: ".var_export($session_name, true), 'DEBUG', 'auth');
        }*/

        return parent::__construct($framework);
    }

    /**
     * Authentifie l'utilisateur via un service OpenID Connect (OAuth).
     *
     * @param  array  $data  Données concernant l'utilisateur à authentifier.
     *
     * @return array   format: (bool $authenticated, string $message, array $data)
     */
    public function authenticate(array $data) {
        $this->framework->log(__METHOD__, 'BEGIN', 'DEBUG', 'openid');

        // si l'authenfication par SSO n'est pas activée
        if (! isset($this->framework->config['enable_openid_login']) || ! $this->framework->config['enable_openid_login']) {
            return array(false,
                __("Connexion par OpenID Connect désactivée. Contactez votre administrateur."),
                array());
        }

        if (!empty($_GET)) {
            $this->framework->log(__METHOD__, '-- GET --'.PHP_EOL.var_export($_GET, true), 'DEBUG', 'openid');
        }
        if (!empty($_POST)) {
            $this->framework->log(__METHOD__, '-- POST --'.PHP_EOL.var_export($_POST, true), 'DEBUG', 'openid');
        }
        if (!empty($_SESSION)) {
            $this->framework->log(__METHOD__, '-- SESSION --'.PHP_EOL.var_export($_SESSION, true), 'DEBUG', 'openid');
        }

        $this->framework->log(__METHOD__, '-- INIT client --', 'DEBUG', 'openid');
        $this->framework->log(__METHOD__, '         provider: '.$this->provider_url, 'DEBUG', 'openid');
        $this->framework->log(__METHOD__, '  application key: '.substr($this->application_id, 0, 8).'…', 'DEBUG', 'openid');
        $this->framework->log(__METHOD__, '   private secret: '.substr($this->application_secret, 0, 8).'…', 'DEBUG', 'openid');
        $oidc = new OpenIDConnectClient($this->provider_url, $this->application_id, $this->application_secret);
        $this->framework->log(__METHOD__, $oidc ? (' OIDC (php class): '.get_class($oidc)) : 'OIDC (php result): '.var_export($oidc, true), 'DEBUG', 'openid');
        $oidc->setRedirectURL($this->redirect_url);
        $this->framework->log(__METHOD__, '-- CONFIGURE client --', 'DEBUG', 'openid');
        $this->framework->log(__METHOD__, '         redirect: '.$this->redirect_url, 'DEBUG', 'openid');
        $this->framework->log(__METHOD__, '-- AUTHENTICATION --', 'DEBUG', 'openid');
        $authenticated = $oidc->authenticate();
        $this->framework->log(__METHOD__, var_export($authenticated, true), 'DEBUG', 'openid');
        $authenticated = boolval($authenticated);
        $auth_data = array();
        if ($authenticated) {
            /*$this->framework->log(__METHOD__, "getting user infos ...", 'DEBUG', 'openid');
            foreach(array(
                "ID" => 'sub',
                "Full name" => 'name',
                "GitLab username" => 'nickname',
                "Email address" => 'email',
                "Email address was verified" => 'email_verified',
            ) as $desc => $key) {
            $this->framework->log(__METHOD__, "   - $desc: ".var_export($oidc->requestUserInfo($key), true), 'DEBUG', 'openid');
            }*/

            $this->framework->log(__METHOD__, "getting user login from attribute: ".
                var_export($this->user_attribute_for_login, true)." ...", 'DEBUG', 'openid');
            $login = $oidc->requestUserInfo($this->user_attribute_for_login);
            $this->framework->log(__METHOD__, "user login: ".var_export($login, true), 'DEBUG', 'openid');
            $auth_data = array('login' => $login);
        }
        return array($authenticated, '', $auth_data);
    }
}
