180852c15SAndreas Gohr<?php 280852c15SAndreas Gohr/** 380852c15SAndreas Gohr * DokuWiki Plugin oauth (Auth Component) 480852c15SAndreas Gohr * 580852c15SAndreas Gohr * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 680852c15SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 780852c15SAndreas Gohr */ 880852c15SAndreas Gohr 980852c15SAndreas Gohr// must be run within Dokuwiki 1080852c15SAndreas Gohrif(!defined('DOKU_INC')) die(); 1180852c15SAndreas Gohr 12f10e09e2SAndreas Gohrclass auth_plugin_oauth extends auth_plugin_authplain { 1380852c15SAndreas Gohr 14f866280eSAndreas Gohr /** 15f866280eSAndreas Gohr * Constructor 16f866280eSAndreas Gohr * 17f866280eSAndreas Gohr * Sets capabilities. 18f866280eSAndreas Gohr */ 1980852c15SAndreas Gohr public function __construct() { 20f10e09e2SAndreas Gohr parent::__construct(); 2180852c15SAndreas Gohr 22f10e09e2SAndreas Gohr $this->cando['external'] = true; 2380852c15SAndreas Gohr } 2480852c15SAndreas Gohr 25f866280eSAndreas Gohr /** 26f866280eSAndreas Gohr * Handle the login 27f866280eSAndreas Gohr * 28f866280eSAndreas Gohr * This either trusts the session data (if any), processes the second oAuth step or simply 29f866280eSAndreas Gohr * executes a normal plugin against local users. 30f866280eSAndreas Gohr * 31f866280eSAndreas Gohr * @param string $user 32f866280eSAndreas Gohr * @param string $pass 33f866280eSAndreas Gohr * @param bool $sticky 34f866280eSAndreas Gohr * @return bool 35f866280eSAndreas Gohr */ 36f10e09e2SAndreas Gohr function trustExternal($user, $pass, $sticky = false) { 37a7a8f46aSAndreas Gohr global $conf; 38a7a8f46aSAndreas Gohr global $USERINFO; 3980852c15SAndreas Gohr 402e94f0b8SAndreas Gohr // are we in login progress? 412e94f0b8SAndreas Gohr if(isset($_SESSION[DOKU_COOKIE]['oauth-inprogress'])) { 422e94f0b8SAndreas Gohr $servicename = $_SESSION[DOKU_COOKIE]['oauth-inprogress']['service']; 432e94f0b8SAndreas Gohr $page = $_SESSION[DOKU_COOKIE]['oauth-inprogress']['id']; 442e94f0b8SAndreas Gohr 452e94f0b8SAndreas Gohr unset($_SESSION[DOKU_COOKIE]['oauth-inprogress']); 462e94f0b8SAndreas Gohr } 4780852c15SAndreas Gohr 48a7a8f46aSAndreas Gohr // check session for existing oAuth login data 49a7a8f46aSAndreas Gohr $session = $_SESSION[DOKU_COOKIE]['auth']; 502e94f0b8SAndreas Gohr if(!isset($servicename) && isset($session['oauth'])) { 51a7a8f46aSAndreas Gohr $servicename = $session['oauth']; 52a7a8f46aSAndreas Gohr // check if session data is still considered valid 53a7a8f46aSAndreas Gohr if(($session['time'] >= time() - $conf['auth_security_timeout']) && 54f866280eSAndreas Gohr ($session['buid'] == auth_browseruid()) 55f866280eSAndreas Gohr ) { 5680852c15SAndreas Gohr 57a7a8f46aSAndreas Gohr $_SERVER['REMOTE_USER'] = $session['user']; 58a7a8f46aSAndreas Gohr $USERINFO = $session['info']; 5980852c15SAndreas Gohr return true; 60f10e09e2SAndreas Gohr } 6180852c15SAndreas Gohr } 6280852c15SAndreas Gohr 63a7a8f46aSAndreas Gohr // either we're in oauth login or a previous log needs to be rechecked 642e94f0b8SAndreas Gohr if(isset($servicename)) { 65a7a8f46aSAndreas Gohr /** @var helper_plugin_oauth $hlp */ 66a7a8f46aSAndreas Gohr $hlp = plugin_load('helper', 'oauth'); 67a7a8f46aSAndreas Gohr $service = $hlp->loadService($servicename); 68a7a8f46aSAndreas Gohr if(is_null($service)) return false; 69a7a8f46aSAndreas Gohr 70a7a8f46aSAndreas Gohr if($service->checkToken()) { 71*213f4618SMichael Große 72*213f4618SMichael Große 73a7a8f46aSAndreas Gohr $uinfo = $service->getUser(); 74f866280eSAndreas Gohr 751025aad7SAndreas Gohr $uinfo['user'] = $this->cleanUser((string) $uinfo['user']); 761025aad7SAndreas Gohr if(!$uinfo['name']) $uinfo['name'] = $uinfo['user']; 771025aad7SAndreas Gohr 781025aad7SAndreas Gohr if(!$uinfo['user'] || !$uinfo['mail']) { 791025aad7SAndreas Gohr msg("$servicename did not provide the needed user info. Can't log you in", -1); 801025aad7SAndreas Gohr return false; 811025aad7SAndreas Gohr } 821025aad7SAndreas Gohr 83f866280eSAndreas Gohr // see if the user is known already 84f866280eSAndreas Gohr $user = $this->getUserByEmail($uinfo['mail']); 85f866280eSAndreas Gohr if($user) { 86f866280eSAndreas Gohr $sinfo = $this->getUserData($user); 873c0138dbSAndreas Gohr // check if the user allowed access via this service 883c0138dbSAndreas Gohr if(!in_array($this->cleanGroup($servicename), $sinfo['grps'])) { 893c0138dbSAndreas Gohr msg(sprintf($this->getLang('authnotenabled'), $servicename), -1); 903c0138dbSAndreas Gohr return false; 913c0138dbSAndreas Gohr } 92f866280eSAndreas Gohr $uinfo['user'] = $user; 93f866280eSAndreas Gohr $uinfo['name'] = $sinfo['name']; 94f866280eSAndreas Gohr $uinfo['grps'] = array_merge((array) $uinfo['grps'], $sinfo['grps']); 95f866280eSAndreas Gohr } else { 96f866280eSAndreas Gohr // new user, create him - making sure the login is unique by adding a number if needed 97f866280eSAndreas Gohr $user = $uinfo['user']; 98f866280eSAndreas Gohr $count = ''; 99f866280eSAndreas Gohr while($this->getUserData($user . $count)) { 100f866280eSAndreas Gohr if($count) { 101f866280eSAndreas Gohr $count++; 102f866280eSAndreas Gohr } else { 103f866280eSAndreas Gohr $count = 1; 104f866280eSAndreas Gohr } 105f866280eSAndreas Gohr } 106f866280eSAndreas Gohr $user = $user . $count; 107f866280eSAndreas Gohr $uinfo['user'] = $user; 1086047eb11SMichael Große $groups_on_creation = array(); 1096047eb11SMichael Große $groups_on_creation[] = $conf['defaultgroup']; 1106047eb11SMichael Große $groups_on_creation[] = $this->cleanGroup($servicename); // add service as group 1116047eb11SMichael Große $uinfo['grps'] = array_merge((array) $uinfo['grps'], $groups_on_creation); 112f866280eSAndreas Gohr 1136c23164dSMichael Große $ok = $this->triggerUserMod('create',array($user, auth_pwgen($user), $uinfo['name'], $uinfo['mail'], 1146c23164dSMichael Große $groups_on_creation)); 115caa5ded4SAndreas Gohr if(!$ok) { 116caa5ded4SAndreas Gohr msg('something went wrong creating your user account. please try again later.', -1); 117caa5ded4SAndreas Gohr return false; 118caa5ded4SAndreas Gohr } 119caa5ded4SAndreas Gohr 120caa5ded4SAndreas Gohr // send notification about the new user 121caa5ded4SAndreas Gohr $subscription = new Subscription(); 122caa5ded4SAndreas Gohr $subscription->send_register($user, $uinfo['name'], $uinfo['mail']); 123f866280eSAndreas Gohr } 124f866280eSAndreas Gohr 125f866280eSAndreas Gohr // set user session 126a7a8f46aSAndreas Gohr $this->setUserSession($uinfo, $servicename); 127*213f4618SMichael Große 128*213f4618SMichael Große $cookie = base64_encode($user).'|'.((int) $sticky).'|'.base64_encode('oauth').'|'.base64_encode($servicename); 129*213f4618SMichael Große $cookieDir = empty($conf['cookiedir']) ? DOKU_REL : $conf['cookiedir']; 130*213f4618SMichael Große $time = $sticky ? (time() + 60 * 60 * 24 * 365) : 0; 131*213f4618SMichael Große setcookie(DOKU_COOKIE,$cookie, $time, $cookieDir, '',($conf['securecookie'] && is_ssl()), true); 132*213f4618SMichael Große 1334485a349SMichael Große if(isset($page)) { 1344485a349SMichael Große send_redirect(wl($page)); 1354485a349SMichael Große } 136a7a8f46aSAndreas Gohr return true; 137*213f4618SMichael Große } else { 138*213f4618SMichael Große $this->relogin($servicename); 139a7a8f46aSAndreas Gohr } 140a7a8f46aSAndreas Gohr 141936b9c9cSMichael Große unset($_SESSION[DOKU_COOKIE]['auth']); 142a7a8f46aSAndreas Gohr return false; // something went wrong during oAuth login 143*213f4618SMichael Große } elseif (isset($_COOKIE[DOKU_COOKIE])) { 144*213f4618SMichael Große global $INPUT; 145*213f4618SMichael Große //try cookie 146*213f4618SMichael Große list($cookieuser, $cookiesticky, $auth, $servicename) = explode('|', $_COOKIE[DOKU_COOKIE]); 147*213f4618SMichael Große $cookieuser = base64_decode($cookieuser, true); 148*213f4618SMichael Große $auth = base64_decode($auth, true); 149*213f4618SMichael Große $servicename = base64_decode($servicename, true); 150*213f4618SMichael Große if ($auth === 'oauth') { 151*213f4618SMichael Große $this->relogin($servicename); 152*213f4618SMichael Große } 15380852c15SAndreas Gohr } 15480852c15SAndreas Gohr 155a7a8f46aSAndreas Gohr // do the "normal" plain auth login via form 156a7a8f46aSAndreas Gohr return auth_login($user, $pass, $sticky); 157a7a8f46aSAndreas Gohr } 15880852c15SAndreas Gohr 159*213f4618SMichael Große protected function relogin($servicename) { 160*213f4618SMichael Große global $INPUT; 161*213f4618SMichael Große 162*213f4618SMichael Große /** @var helper_plugin_oauth $hlp */ 163*213f4618SMichael Große $hlp = plugin_load('helper', 'oauth'); 164*213f4618SMichael Große $service = $hlp->loadService($servicename); 165*213f4618SMichael Große if(is_null($service)) return false; 166*213f4618SMichael Große 167*213f4618SMichael Große // remember service in session 168*213f4618SMichael Große session_start(); 169*213f4618SMichael Große $_SESSION[DOKU_COOKIE]['oauth-inprogress']['service'] = $servicename; 170*213f4618SMichael Große $_SESSION[DOKU_COOKIE]['oauth-inprogress']['id'] = $INPUT->str('id'); 171*213f4618SMichael Große 172*213f4618SMichael Große $str_vars = array('wikitext', 'prefix', 'suffix', 'summary', 'sectok', 'target', 'range', 'rev', 'at'); 173*213f4618SMichael Große foreach ($str_vars as $input_var) { 174*213f4618SMichael Große if ($INPUT->str($input_var) !== '') { 175*213f4618SMichael Große $_SESSION[DOKU_COOKIE]['oauth-done'][$input_var] = $INPUT->str($input_var); 176*213f4618SMichael Große } 177*213f4618SMichael Große 178*213f4618SMichael Große if ($INPUT->post->str($input_var) !== '') { 179*213f4618SMichael Große $_SESSION[DOKU_COOKIE]['oauth-done']['post'][$input_var] = $INPUT->post->str($input_var); 180*213f4618SMichael Große } 181*213f4618SMichael Große 182*213f4618SMichael Große if ($INPUT->get->str($input_var) !== '') { 183*213f4618SMichael Große $_SESSION[DOKU_COOKIE]['oauth-done']['get'][$input_var] = $INPUT->get->str($input_var); 184*213f4618SMichael Große } 185*213f4618SMichael Große } 186*213f4618SMichael Große 187*213f4618SMichael Große if (is_array($INPUT->post->param('do'))) { 188*213f4618SMichael Große $doPost = key($INPUT->post->arr('do')); 189*213f4618SMichael Große } else { 190*213f4618SMichael Große $doPost = $INPUT->post->str('do'); 191*213f4618SMichael Große } 192*213f4618SMichael Große $doGet = $INPUT->get->str('do'); 193*213f4618SMichael Große if (!empty($doPost)) { 194*213f4618SMichael Große $_SESSION[DOKU_COOKIE]['oauth-done']['do'] = $doPost; 195*213f4618SMichael Große } elseif (!empty($doGet)) { 196*213f4618SMichael Große $_SESSION[DOKU_COOKIE]['oauth-done']['do'] = $doGet; 197*213f4618SMichael Große } 198*213f4618SMichael Große 199*213f4618SMichael Große session_write_close(); 200*213f4618SMichael Große 201*213f4618SMichael Große $service->login(); 202*213f4618SMichael Große } 203*213f4618SMichael Große 204a7a8f46aSAndreas Gohr /** 205a7a8f46aSAndreas Gohr * @param array $data 206a7a8f46aSAndreas Gohr * @param string $service 207a7a8f46aSAndreas Gohr */ 208a7a8f46aSAndreas Gohr protected function setUserSession($data, $service) { 209a7a8f46aSAndreas Gohr global $USERINFO; 210a7a8f46aSAndreas Gohr global $conf; 211a7a8f46aSAndreas Gohr 212a7a8f46aSAndreas Gohr // set up groups 213a7a8f46aSAndreas Gohr if(!is_array($data['grps'])) { 214a7a8f46aSAndreas Gohr $data['grps'] = array(); 215a7a8f46aSAndreas Gohr } 216a7a8f46aSAndreas Gohr $data['grps'][] = $this->cleanGroup($service); 217f866280eSAndreas Gohr $data['grps'] = array_unique($data['grps']); 21880852c15SAndreas Gohr 219f10e09e2SAndreas Gohr $USERINFO = $data; 220f10e09e2SAndreas Gohr $_SERVER['REMOTE_USER'] = $data['user']; 221f10e09e2SAndreas Gohr $_SESSION[DOKU_COOKIE]['auth']['user'] = $data['user']; 222f10e09e2SAndreas Gohr $_SESSION[DOKU_COOKIE]['auth']['pass'] = $data['pass']; 223f10e09e2SAndreas Gohr $_SESSION[DOKU_COOKIE]['auth']['info'] = $USERINFO; 224a7a8f46aSAndreas Gohr $_SESSION[DOKU_COOKIE]['auth']['buid'] = auth_browseruid(); 225a7a8f46aSAndreas Gohr $_SESSION[DOKU_COOKIE]['auth']['time'] = time(); 226a7a8f46aSAndreas Gohr $_SESSION[DOKU_COOKIE]['auth']['oauth'] = $service; 22780852c15SAndreas Gohr } 22880852c15SAndreas Gohr 229f866280eSAndreas Gohr /** 230e32c3607SAndreas Gohr * Unset additional stuff in session on logout 231e32c3607SAndreas Gohr */ 232e32c3607SAndreas Gohr public function logOff() { 233e32c3607SAndreas Gohr parent::logOff(); 234e32c3607SAndreas Gohr 235e32c3607SAndreas Gohr if(isset($_SESSION[DOKU_COOKIE]['auth']['buid'])) { 236e32c3607SAndreas Gohr unset($_SESSION[DOKU_COOKIE]['auth']['buid']); 237e32c3607SAndreas Gohr } 238e32c3607SAndreas Gohr if(isset($_SESSION[DOKU_COOKIE]['auth']['time'])) { 239e32c3607SAndreas Gohr unset($_SESSION[DOKU_COOKIE]['auth']['time']); 240e32c3607SAndreas Gohr } 241e32c3607SAndreas Gohr if(isset($_SESSION[DOKU_COOKIE]['auth']['oauth'])) { 242e32c3607SAndreas Gohr unset($_SESSION[DOKU_COOKIE]['auth']['oauth']); 243e32c3607SAndreas Gohr } 244e32c3607SAndreas Gohr } 245e32c3607SAndreas Gohr 246e32c3607SAndreas Gohr /** 247f866280eSAndreas Gohr * Find a user by his email address 248f866280eSAndreas Gohr * 249f866280eSAndreas Gohr * @param $mail 250f866280eSAndreas Gohr * @return bool|string 251f866280eSAndreas Gohr */ 25238378fbbSAndreas Gohr protected function getUserByEmail($mail) { 253f866280eSAndreas Gohr if($this->users === null) $this->_loadUserData(); 25438378fbbSAndreas Gohr $mail = strtolower($mail); 255f866280eSAndreas Gohr 256f866280eSAndreas Gohr foreach($this->users as $user => $uinfo) { 257f866280eSAndreas Gohr if(strtolower($uinfo['mail']) == $mail) return $user; 25838378fbbSAndreas Gohr } 25938378fbbSAndreas Gohr 260f866280eSAndreas Gohr return false; 261f866280eSAndreas Gohr } 26238378fbbSAndreas Gohr 263f866280eSAndreas Gohr /** 264f866280eSAndreas Gohr * Enhance function to check aainst duplicate emails 265f866280eSAndreas Gohr * 266f866280eSAndreas Gohr * @param string $user 267f866280eSAndreas Gohr * @param string $pwd 268f866280eSAndreas Gohr * @param string $name 269f866280eSAndreas Gohr * @param string $mail 270f866280eSAndreas Gohr * @param null $grps 271f866280eSAndreas Gohr * @return bool|null|string 272f866280eSAndreas Gohr */ 273f866280eSAndreas Gohr public function createUser($user, $pwd, $name, $mail, $grps = null) { 274f866280eSAndreas Gohr if($this->getUserByEmail($mail)) { 275f866280eSAndreas Gohr msg($this->getLang('emailduplicate'), -1); 276f866280eSAndreas Gohr return false; 277f866280eSAndreas Gohr } 278f866280eSAndreas Gohr 27938378fbbSAndreas Gohr return parent::createUser($user, $pwd, $name, $mail, $grps); 28038378fbbSAndreas Gohr } 28138378fbbSAndreas Gohr 282f866280eSAndreas Gohr /** 283f866280eSAndreas Gohr * Enhance function to check aainst duplicate emails 284f866280eSAndreas Gohr * 285f866280eSAndreas Gohr * @param string $user 286f866280eSAndreas Gohr * @param array $changes 287f866280eSAndreas Gohr * @return bool 288f866280eSAndreas Gohr */ 28938378fbbSAndreas Gohr public function modifyUser($user, $changes) { 2903c0138dbSAndreas Gohr global $conf; 2913c0138dbSAndreas Gohr 2923c0138dbSAndreas Gohr if(isset($changes['mail'])) { 2933c0138dbSAndreas Gohr $found = $this->getUserByEmail($changes['mail']); 2943c0138dbSAndreas Gohr if($found != $user) { 295f866280eSAndreas Gohr msg($this->getLang('emailduplicate'), -1); 296f866280eSAndreas Gohr return false; 297f866280eSAndreas Gohr } 2983c0138dbSAndreas Gohr } 29938378fbbSAndreas Gohr 3003c0138dbSAndreas Gohr $ok = parent::modifyUser($user, $changes); 3013c0138dbSAndreas Gohr 3023c0138dbSAndreas Gohr // refresh session cache 3033c0138dbSAndreas Gohr touch($conf['cachedir'] . '/sessionpurge'); 3043c0138dbSAndreas Gohr 3053c0138dbSAndreas Gohr return $ok; 30638378fbbSAndreas Gohr } 30738378fbbSAndreas Gohr 30880852c15SAndreas Gohr} 30980852c15SAndreas Gohr 31080852c15SAndreas Gohr// vim:ts=4:sw=4:et: 311