xref: /plugin/authssocas/auth.php (revision d10b5556242e78d8a430c323b91984ec16415a46)
1*d10b5556SXylle<?php
2*d10b5556SXylle
3*d10b5556SXylle/**
4*d10b5556SXylle * CAS authentication plugin
5*d10b5556SXylle *
6*d10b5556SXylle * @licence   GPL 2 (http://www.gnu.org/licenses/gpl.html)
7*d10b5556SXylle * @author    Xylle, Fabian Bircher
8*d10b5556SXylle * @version   0.0.3
9*d10b5556SXylle *
10*d10b5556SXylle */
11*d10b5556SXylle
12*d10b5556SXylleuse dokuwiki\Extension\AuthPlugin;
13*d10b5556SXylle
14*d10b5556SXylle
15*d10b5556SXylleclass auth_plugin_authssocas extends AuthPlugin
16*d10b5556SXylle{
17*d10b5556SXylle    /**
18*d10b5556SXylle     * @var array|mixed
19*d10b5556SXylle     */
20*d10b5556SXylle    private array $options = array();
21*d10b5556SXylle
22*d10b5556SXylle    private ?string $logfileuser = null;
23*d10b5556SXylle
24*d10b5556SXylle    public function __construct()
25*d10b5556SXylle    {
26*d10b5556SXylle        global $conf;
27*d10b5556SXylle        parent::__construct();
28*d10b5556SXylle        require_once __DIR__ . '/vendor/autoload.php';
29*d10b5556SXylle
30*d10b5556SXylle        // Vérifie si la classe phpCAS existe
31*d10b5556SXylle        if (!class_exists('phpCAS')) {
32*d10b5556SXylle            msg("CAS err: phpCAS class not found.", -1);
33*d10b5556SXylle            $this->success = false;
34*d10b5556SXylle            return;
35*d10b5556SXylle        }
36*d10b5556SXylle        // Vérifie si l'extension curl existe
37*d10b5556SXylle        if (!extension_loaded("curl")) {
38*d10b5556SXylle            msg("CAS err: CURL php extension not found.", -1);
39*d10b5556SXylle            $this->success = false;
40*d10b5556SXylle            return;
41*d10b5556SXylle        }
42*d10b5556SXylle        // Définition des capacités de l'extension d'authentification
43*d10b5556SXylle        $this->cando['external'] = true;
44*d10b5556SXylle//        $this->cando['login'] = true;
45*d10b5556SXylle//        $this->cando['logout'] = true;
46*d10b5556SXylle
47*d10b5556SXylle        // Création d'un journal des connexions, si un fichier est défini.
48*d10b5556SXylle        if ($this->getConf('logfileuser')) {
49*d10b5556SXylle            $this->logfileuser = $conf['logdir'] . "/" . $this->getConf('logfileuser');
50*d10b5556SXylle        }
51*d10b5556SXylle        if (!is_null($this->logfileuser) and !@is_readable($this->logfileuser)) {
52*d10b5556SXylle            if (!fopen($this->logfileuser, 'a')) {
53*d10b5556SXylle                msg("plainCAS: The CAS log users file could not be opened.", -1);
54*d10b5556SXylle                $this->success = false;
55*d10b5556SXylle            }
56*d10b5556SXylle        }
57*d10b5556SXylle
58*d10b5556SXylle
59*d10b5556SXylle        // Chargement des options
60*d10b5556SXylle        $this->options['debug'] = $this->getConf('debug');
61*d10b5556SXylle        $this->options['group_attribut'] = $this->getConf('group_attribut');
62*d10b5556SXylle        $this->options['handlelogoutrequest'] = $this->getConf('handlelogoutrequest');
63*d10b5556SXylle        $this->options['handlelogoutrequestTrustedHosts'] = $this->getConf('handlelogoutrequestTrustedHosts');
64*d10b5556SXylle        $this->options['mail_attribut'] = $this->getConf('mail_attribut');
65*d10b5556SXylle        $this->options['name_attribut'] = $this->getConf('name_attribut');
66*d10b5556SXylle        $this->options['port'] = $this->getConf('port');
67*d10b5556SXylle        $this->options['samlValidate'] = $this->getConf('samlValidate');
68*d10b5556SXylle        $this->options['server'] = $this->getConf('server');
69*d10b5556SXylle        $this->options['rootcas'] = $this->getConf('rootcas');
70*d10b5556SXylle        $this->options['uid_attribut'] = $this->getConf('uid_attribut');
71*d10b5556SXylle        $this->options['cacert'] = $this->getConf('cacert');
72*d10b5556SXylle
73*d10b5556SXylle        $server_version = CAS_VERSION_2_0;
74*d10b5556SXylle        if ($this->getOption("samlValidate")) {
75*d10b5556SXylle            $server_version = SAML_VERSION_1_1;
76*d10b5556SXylle        }
77*d10b5556SXylle
78*d10b5556SXylle        if ($this->getOption("debug")) {
79*d10b5556SXylle            phpCAS::setLogger();
80*d10b5556SXylle            phpCAS::setVerbose(true);
81*d10b5556SXylle        }
82*d10b5556SXylle
83*d10b5556SXylle        if (!DOKU_BASE == "/") {
84*d10b5556SXylle            $service_base_url = str_replace(DOKU_BASE, "", DOKU_URL);
85*d10b5556SXylle        } else {
86*d10b5556SXylle            $service_base_url = DOKU_URL;
87*d10b5556SXylle        }
88*d10b5556SXylle
89*d10b5556SXylle        // Configuration du client CAS
90*d10b5556SXylle        phpCAS::client(
91*d10b5556SXylle            $server_version,
92*d10b5556SXylle            $this->getOption('server'),
93*d10b5556SXylle            (int)$this->getOption('port'),
94*d10b5556SXylle            $this->getOption('rootcas'),
95*d10b5556SXylle            $service_base_url
96*d10b5556SXylle        );
97*d10b5556SXylle
98*d10b5556SXylle        if ($this->getConf('autologin')) {
99*d10b5556SXylle            phpCAS::setCacheTimesForAuthRecheck(-1);
100*d10b5556SXylle        } else {
101*d10b5556SXylle            phpCAS::setCacheTimesForAuthRecheck(1);
102*d10b5556SXylle        }
103*d10b5556SXylle
104*d10b5556SXylle        // Gestion de l'autorité de certification du certificat du serveur CAS pour la bibliothèque php_curl
105*d10b5556SXylle        $cas_cacert_file = DOKU_CONF . 'authssocas.cacert.pem';
106*d10b5556SXylle        if ($this->getOption('cacert')) {
107*d10b5556SXylle            if (!io_saveFile($cas_cacert_file, $this->getOption('cacert'))) {
108*d10b5556SXylle                msg('The ' . $cas_cacert_file . ' file is not writable. Please inform the Wiki-Admin', -1);
109*d10b5556SXylle            }
110*d10b5556SXylle            phpCAS::setCasServerCACert($cas_cacert_file);
111*d10b5556SXylle        } else {
112*d10b5556SXylle            phpCAS::setNoCasServerValidation();
113*d10b5556SXylle        }
114*d10b5556SXylle
115*d10b5556SXylle        // Gestion de la déconnexion sur le serveur CAS
116*d10b5556SXylle        if ($this->getOption('handlelogoutrequest')) {
117*d10b5556SXylle            phpCAS::handleLogoutRequests(true, $this->getOption('handlelogoutrequestTrustedHosts'));
118*d10b5556SXylle        } else {
119*d10b5556SXylle            phpCAS::handleLogoutRequests(false);
120*d10b5556SXylle        }
121*d10b5556SXylle    }
122*d10b5556SXylle
123*d10b5556SXylle    /**
124*d10b5556SXylle     *
125*d10b5556SXylle     * Récupère les options
126*d10b5556SXylle     *  Transforme en tableau les URL de notification de la déconnexion pour les serveurs CAS
127*d10b5556SXylle     *
128*d10b5556SXylle     * @param $optionName
129*d10b5556SXylle     * @return array|mixed|string[]|null
130*d10b5556SXylle     */
131*d10b5556SXylle    private function getOption($optionName)
132*d10b5556SXylle    {
133*d10b5556SXylle        if (isset($this->options[$optionName])) {
134*d10b5556SXylle            switch ($optionName) {
135*d10b5556SXylle                case 'handlelogoutrequestTrustedHosts':
136*d10b5556SXylle                    $arr = explode(',', $this->options[$optionName]);
137*d10b5556SXylle                    foreach ($arr as $key => $item) {
138*d10b5556SXylle                        $arr[$key] = trim($item);
139*d10b5556SXylle                    }
140*d10b5556SXylle                    return $arr;
141*d10b5556SXylle                default:
142*d10b5556SXylle                    return $this->options[$optionName];
143*d10b5556SXylle            }
144*d10b5556SXylle        }
145*d10b5556SXylle        return NULL;
146*d10b5556SXylle    }
147*d10b5556SXylle
148*d10b5556SXylle    /**
149*d10b5556SXylle     *
150*d10b5556SXylle     * Transfert de la demande de connexion au serveur CAS
151*d10b5556SXylle     *
152*d10b5556SXylle     * @return void
153*d10b5556SXylle     * @noinspection PhpUnused
154*d10b5556SXylle     */
155*d10b5556SXylle    public function logIn()
156*d10b5556SXylle    {
157*d10b5556SXylle        global $ID;
158*d10b5556SXylle        $login_url = DOKU_URL . 'doku.php?id=' . $ID;
159*d10b5556SXylle
160*d10b5556SXylle        phpCAS::setFixedServiceURL($login_url);
161*d10b5556SXylle        phpCAS::forceAuthentication();
162*d10b5556SXylle    }
163*d10b5556SXylle
164*d10b5556SXylle    /**
165*d10b5556SXylle     *
166*d10b5556SXylle     * Déconnexion de l'utilisateur avec prise en compte de la déconnexion générale du CAS
167*d10b5556SXylle     *
168*d10b5556SXylle     * @return void
169*d10b5556SXylle     */
170*d10b5556SXylle    public function logOff(): void
171*d10b5556SXylle    {
172*d10b5556SXylle        global $ID;
173*d10b5556SXylle
174*d10b5556SXylle        @session_start();
175*d10b5556SXylle        session_destroy();
176*d10b5556SXylle        if ($this->getOption('handlelogoutrequest')) {
177*d10b5556SXylle            $logout_url = DOKU_URL . 'doku.php?id=' . $ID;
178*d10b5556SXylle            @phpCAS::logoutWithRedirectService($logout_url);
179*d10b5556SXylle        } else {
180*d10b5556SXylle            phpCAS::handleLogoutRequests();
181*d10b5556SXylle            unset($_SESSION);
182*d10b5556SXylle        }
183*d10b5556SXylle    }
184*d10b5556SXylle
185*d10b5556SXylle    public function trustExternal($user, $pass, $sticky = false): bool
186*d10b5556SXylle    {
187*d10b5556SXylle        global $USERINFO;
188*d10b5556SXylle
189*d10b5556SXylle        if (!empty($_SESSION[DOKU_COOKIE]['auth']['info'])) {
190*d10b5556SXylle            $USERINFO['name'] = $_SESSION[DOKU_COOKIE]['auth']['info']['name'];
191*d10b5556SXylle            $USERINFO['mail'] = $_SESSION[DOKU_COOKIE]['auth']['info']['mail'];
192*d10b5556SXylle            $USERINFO['grps'] = $_SESSION[DOKU_COOKIE]['auth']['info']['grps'];
193*d10b5556SXylle            $_SERVER['REMOTE_USER'] = $_SESSION[DOKU_COOKIE]['auth']['user'];
194*d10b5556SXylle            return true;
195*d10b5556SXylle        }
196*d10b5556SXylle
197*d10b5556SXylle        if (phpCAS::isAuthenticated() or ($this->getOption('autologin') and phpCAS::checkAuthentication())) {
198*d10b5556SXylle
199*d10b5556SXylle            $USERINFO = $this->cas_user_attributes(phpCAS::getAttributes());
200*d10b5556SXylle            $this->auth_log($USERINFO['uid']);
201*d10b5556SXylle            $_SESSION[DOKU_COOKIE]['auth']['user'] = $USERINFO['uid'];
202*d10b5556SXylle            $_SESSION[DOKU_COOKIE]['auth']['info'] = $USERINFO;
203*d10b5556SXylle            $_SERVER['REMOTE_USER'] = $USERINFO['uid'];
204*d10b5556SXylle            return true;
205*d10b5556SXylle        }
206*d10b5556SXylle
207*d10b5556SXylle        return false;
208*d10b5556SXylle    }
209*d10b5556SXylle
210*d10b5556SXylle    /**
211*d10b5556SXylle     *
212*d10b5556SXylle     * Renvoi les informations de l'utilisateur fournit par le CAS
213*d10b5556SXylle     *
214*d10b5556SXylle     * @param $attributes
215*d10b5556SXylle     * @return array
216*d10b5556SXylle     */
217*d10b5556SXylle    private function cas_user_attributes($attributes): array
218*d10b5556SXylle    {
219*d10b5556SXylle        return array(
220*d10b5556SXylle            'uid' => $attributes[$this->getOption('uid_attribut')],
221*d10b5556SXylle            'name' => $attributes[$this->getOption('name_attribut')],
222*d10b5556SXylle            'mail' => $attributes[$this->getOption('mail_attribut')],
223*d10b5556SXylle            'grps' => $attributes[$this->getOption('group_attribut')],
224*d10b5556SXylle        );
225*d10b5556SXylle    }
226*d10b5556SXylle
227*d10b5556SXylle    /**
228*d10b5556SXylle     *
229*d10b5556SXylle     * Log user connection if the log file is defined
230*d10b5556SXylle     *
231*d10b5556SXylle     * format : DATE|TIME|USER
232*d10b5556SXylle     *
233*d10b5556SXylle     * @param $user
234*d10b5556SXylle     * @return void
235*d10b5556SXylle     */
236*d10b5556SXylle    private function auth_log($user): void
237*d10b5556SXylle    {
238*d10b5556SXylle        if (!is_null($this->logfileuser)) {
239*d10b5556SXylle
240*d10b5556SXylle            $date = (new DateTime('now'))->format('Ymd|H:i:s');
241*d10b5556SXylle
242*d10b5556SXylle            $userline = $date . "|" . $user . PHP_EOL;
243*d10b5556SXylle            if (!io_saveFile($this->logfileuser, $userline, true)) {
244*d10b5556SXylle                msg($this->getLang('writefail'), -1);
245*d10b5556SXylle            }
246*d10b5556SXylle        }
247*d10b5556SXylle    }
248*d10b5556SXylle
249*d10b5556SXylle}
250