Subversion Repositories Applications.wikini

Rev

Rev 66 | Blame | Compare with Previous | Last modification | View Log | RSS feed

<?php

// Remplacement de apache_request_headers pour les vieux serveurs
// http://stackoverflow.com/questions/2916232/call-to-undefined-function-apache-request-headers
if(!function_exists('apache_request_headers')) {
        function apache_request_headers() {
                // Based on: http://www.iana.org/assignments/message-headers/message-headers.xml#perm-headers
                $arrCasedHeaders = array(
                                // HTTP
                                'Dasl'             => 'DASL',
                                'Dav'              => 'DAV',
                                'Etag'             => 'ETag',
                                'Mime-Version'     => 'MIME-Version',
                                'Slug'             => 'SLUG',
                                'Te'               => 'TE',
                                'Www-Authenticate' => 'WWW-Authenticate',
                                // MIME
                                'Content-Md5'      => 'Content-MD5',
                                'Content-Id'       => 'Content-ID',
                                'Content-Features' => 'Content-features',
                );
                $arrHttpHeaders = array();

                foreach($_SERVER as $strKey => $mixValue) {
                        if('HTTP_' !== substr($strKey, 0, 5)) {
                                continue;
                        }

                        $strHeaderKey = strtolower(substr($strKey, 5));

                        if(0 < substr_count($strHeaderKey, '_')) {
                                $arrHeaderKey = explode('_', $strHeaderKey);
                                $arrHeaderKey = array_map('ucfirst', $arrHeaderKey);
                                $strHeaderKey = implode('-', $arrHeaderKey);
                        }
                        else {
                                $strHeaderKey = ucfirst($strHeaderKey);
                        }

                        if(array_key_exists($strHeaderKey, $arrCasedHeaders)) {
                                $strHeaderKey = $arrCasedHeaders[$strHeaderKey];
                        }

                        $arrHttpHeaders[$strHeaderKey] = $mixValue;
                }
                return $arrHttpHeaders;
        }
}

class identificationSso {

        private $wiki = null;
        private $config = null;

        private $cookie_tentative_identification = "";
        private $delai_tentative_identification = 60;
        
        private $auth_header = 'Authorization';

        public function __construct($wiki) {
                $this->wiki = $wiki;
                $this->config = $wiki->config;
                $this->auth_header = !empty($this->config['sso_auth_header']) ? $this->config['sso_auth_header'] : $this->auth_header;
                $this->cookie_tentative_identification = 'wikini_sso_tentative_identification';
        }

        function getToken() {
                // Premier essai, dans le header
                $headers = @apache_request_headers();
                $token = !empty($headers['Authorization']) ? $headers['Authorization'] : null;
                // Eventuellement, le jeton a pu être passé dans un header non standard, comme dans 
                // le cas où le header Authorization est supprimé par le mod cgi d'apache
                // Dans ce cas là on vérifie aussi dans un header alternatif si celui ci a été renseigné
                if($token == null && $this->auth_header != 'Authorization') {
                        $token = !empty($headers[$this->auth_header]) ? $headers[$this->auth_header] : null;
                }

                // Sinon dans $_REQUEST ?
                if($token == null) {
                        $token = !empty($_REQUEST['Authorization']) ? $_REQUEST['Authorization'] : null;
                }
                
                // Sinon dans $_COOKIE ?
                if($token == null) {
                        $token = !empty($_COOKIE['tb_auth']) ? $_COOKIE['tb_auth'] : null;
                }

                return $token;
        }

        function decoderToken($token) {
                $token_parts = explode('.', $token);
                return json_decode(base64_decode($token_parts[1]), true);
        }

        function getPage() {
                return !empty($this->wiki->page) ? $this->wiki->page['tag'] : 'PagePrincipale';
        }

        // http://stackoverflow.com/questions/1251582/beautiful-way-to-remove-get-variables-with-php?lq=1
        function supprimerUrlVar($url, $var) {
                 return rtrim(preg_replace('/([?&])'.$var.'=[^&]+(&|$)/','$1',$url), '&?');
        }

        function getInfosCookie() {
                $infos = null;
                if(!empty($_COOKIE[$this->cookie_tentative_identification])) {
                        $infos = json_decode($_COOKIE[$this->cookie_tentative_identification], true);
                }
                return $infos;
        }

        function setInfosCookie($infos) {
                $infos['expire'] = !empty($infos['expire']) ? $infos['expire'] : 0;
                setcookie($this->cookie_tentative_identification, json_encode($infos), $infos['expire'], $this->wiki->CookiePath);
        }

        function verifierEtInsererUtilisateurParJeton($jeton_rafraichi) {
                if(!empty($jeton_rafraichi['session']) && $jeton_rafraichi['session'] == true) {
                        $token_decode = $this->decoderToken($jeton_rafraichi['token']);
                        
                        $nom_wiki = $token_decode['nomWiki'];
                        $courriel = $token_decode['sub'];
                        
                        $utilisateur_wiki_existe = $this->wiki->LoadAll("SELECT * FROM  ".$this->wiki->config["table_prefix"]."users ".
                                        "WHERE ".
                                        "name = '".mysql_escape_string($nom_wiki)."' OR ".
                                        "email = '".mysql_escape_string($courriel)."'");
                        
                        // pas inscrit ? on l'ajout à la base de données
                        if(empty($utilisateur_wiki_existe)) {
                                // mot de passe généré à l'arrache, le mieux serait de trouver celui de tela encodé
                                // mais en gérant bien le sso on peut s'en passer car l'utilisateur ne devrait jamais avoir 
                                // à s'identifier par le wiki
                                $pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
                                $pass = substr(str_shuffle(str_repeat($pool, 16)), 0, 16);
                                
                                $this->wiki->Query("insert into ".$this->wiki->config["table_prefix"]."users set ".
                                                "signuptime = now(), ".
                                                "name = '".mysql_escape_string($token_decode['nomWiki'])."', ".
                                                "email = '".mysql_escape_string($token_decode['sub'])."', ".
                                                "password = md5('".mysql_escape_string($pass)."')");
                        } else {
                                // Un utilisateur peut déjà s'être inscrit sur le wiki avec un autre nom que son pseudo
                                $nom_wiki = $utilisateur_wiki_existe[0]['name'];
                                // s'il existe un enregistrement avec ce mail et un autre avec ce nomWiki on garde celui qui correspond au bon courriel
                                foreach($utilisateur_wiki_existe as $utilisateur_wiki) {
                                        if($utilisateur_wiki['email'] == $courriel) {
                                                  $nom_wiki = $utilisateur_wiki['name'];
                                        }
                                }
                        }
                }

                return $nom_wiki;
        }

        function recupererIdentiteConnectee() {
                $infos_cookie = $this->getInfosCookie();
                if($infos_cookie == null || $infos_cookie['tentative_identification'] == false) {       
                        // peut importe si l'annuaire répond oui ou non, on a fait une tentative d'identification
                        // et si on a trouvé quelqu'un on ne réésaiera pas jusqu'à la fermeture du navigateur
                        $infos_cookie = array('tentative_identification' => true, 'expire' => 0);
                        $this->setInfosCookie($infos_cookie);

                        $annuaire_url = $this->wiki->config['sso_url'].'identite';
                        // Attention si le paramètre wiki de l'url est vide, la redirection de retour pose des problèmes
                        $url = $annuaire_url.'?redirect_url='.urlencode($this->wiki->config['base_url'].$this->getPage());

                        header('Location: '.$url);
                        exit;
                } else {
                        $token = $this->getToken();

                        if($token != null) {
                                // On demande à l'annuaire si le jeton est bien valide
                                $jeton_rafraichi = json_decode(file_get_contents($this->wiki->config['sso_url'].'rafraichir?token='.$token), true);
                                $nom_wiki = $this->verifierEtInsererUtilisateurParJeton($jeton_rafraichi);

                                // dans le pire des cas, si on se déconnecte dans une autre application, on sera déconnecté 
                                // lorsque le jeton expirera
                                $infos_cookie = array('tentative_identification' => true, 'expire' => time()+$jeton_rafraichi['duration']);
                                $this->setInfosCookie($infos_cookie);

                                $this->wiki->SetUser($this->wiki->LoadUser($nom_wiki));
                        } else {
                                // personne n'a été trouvé ? on remplace le cookie par un de durée plus courte 
                                // pour rééssayer dans delai_tentative_identification si on en a pas déjà un
                                if($infos_cookie['expire'] == 0) { 
                                        $infos_cookie['expire'] = time()+$this->delai_tentative_identification;
                                        $this->setInfosCookie($infos_cookie);
                                }
                        }
                }
        }

        function recupererIdentiteConnecteePourApi() {          
                $token = $this->getToken();
                if($token != null) {
                        // On demande à l'annuaire si le jeton est bien valide
                        $jeton_rafraichi = json_decode(file_get_contents($this->wiki->config['sso_url'].'rafraichir?token='.$token), true);
                        $nom_wiki = $this->verifierEtInsererUtilisateurParJeton($jeton_rafraichi);
                        $this->wiki->SetUser($this->wiki->LoadUser($nom_wiki));
                }
        }

        function connecterUtilisateur($login, $pass, $url_redirect = null) {
                if(strpos($login, '@') === false) {
                        $utilisateur_wiki = $this->wiki->LoadSingle("SELECT email FROM  ".$this->wiki->config["table_prefix"]."users ".
                        "WHERE name = '".mysql_escape_string($login)."'");

                        $login = !empty($utilisateur_wiki) ? $utilisateur_wiki['email'] : $login;
                        // TODO: si le courriel a changé dans l'annuaire, on devrait mettre à jour les informations 
                        // si on a utilisé le nom wiki pour s'identifier mais le flow du programme rend cela complexe
                }

                $url_redirect = ($url_redirect == null) ? $this->wiki->config['base_url'].'PagePrincipale' : $url_redirect;

                // le cookie de tentative d'identification est remis à zéro pour qu'au rechargement de la page il vérifie l'identité 
                // connectée du nouvel utilisateur
                $infos_cookie = array('tentative_identification' => false, 'expire' => 0);
                $this->setInfosCookie($infos_cookie);
                // On demande à l'annuaire si l'utilisateur est bien valide
                $annuaire_url = $this->wiki->config['sso_url'].'connexion?login='.$login.'&password='.$pass;
                $url = $annuaire_url.'&redirect_url='.urlencode($url_redirect);

                header('Location: '.$url);
                exit;
        }

        function deconnecterUtilisateur($url_redirect = null) {
                $url_redirect = ($url_redirect == null) ? $this->wiki->config['base_url'].'PagePrincipale' : $url_redirect;
                // Suppression d'un eventuel jeton contenu dans l'url
                $url_redirect = $this->supprimerUrlVar($url_redirect, 'Authorization');
                
                $infos_cookie = array('tentative_identification' => false, 'expire' => 0);
                $this->setInfosCookie($infos_cookie);
                // On demande à l'annuaire si l'utilisateur est bien valide
                $annuaire_url = $this->wiki->config['sso_url'].'deconnexion';
                $url = $annuaire_url.'?redirect_url='.urlencode($url_redirect);
                header('Location: '.$url);
                exit;
        }
}
?>