1<?php 2/** 3 * DokuWiki Plugin oauth (Auth Component) 4 * 5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 6 * @author Andreas Gohr <andi@splitbrain.org> 7 */ 8 9// must be run within Dokuwiki 10if(!defined('DOKU_INC')) die(); 11 12class auth_plugin_oauth extends auth_plugin_authplain { 13 14 /** 15 * Constructor 16 * 17 * Sets capabilities. 18 */ 19 public function __construct() { 20 parent::__construct(); 21 22 $this->cando['external'] = true; 23 } 24 25 /** 26 * Handle the login 27 * 28 * This either trusts the session data (if any), processes the second oAuth step or simply 29 * executes a normal plugin against local users. 30 * 31 * @param string $user 32 * @param string $pass 33 * @param bool $sticky 34 * @return bool 35 */ 36 function trustExternal($user, $pass, $sticky = false) { 37 global $conf; 38 global $USERINFO; 39 40 // are we in login progress? 41 if(isset($_SESSION[DOKU_COOKIE]['oauth-inprogress'])) { 42 $servicename = $_SESSION[DOKU_COOKIE]['oauth-inprogress']['service']; 43 $page = $_SESSION[DOKU_COOKIE]['oauth-inprogress']['id']; 44 45 unset($_SESSION[DOKU_COOKIE]['oauth-inprogress']); 46 } 47 48 // check session for existing oAuth login data 49 $session = $_SESSION[DOKU_COOKIE]['auth']; 50 if(!isset($servicename) && isset($session['oauth'])) { 51 $servicename = $session['oauth']; 52 // check if session data is still considered valid 53 if(($session['time'] >= time() - $conf['auth_security_timeout']) && 54 ($session['buid'] == auth_browseruid()) 55 ) { 56 57 $_SERVER['REMOTE_USER'] = $session['user']; 58 $USERINFO = $session['info']; 59 return true; 60 } 61 } 62 63 // either we're in oauth login or a previous log needs to be rechecked 64 if(isset($servicename)) { 65 /** @var helper_plugin_oauth $hlp */ 66 $hlp = plugin_load('helper', 'oauth'); 67 $service = $hlp->loadService($servicename); 68 if(is_null($service)) return false; 69 70 if($service->checkToken()) { 71 72 73 $uinfo = $service->getUser(); 74 75 $uinfo['user'] = $this->cleanUser((string) $uinfo['user']); 76 if(!$uinfo['name']) $uinfo['name'] = $uinfo['user']; 77 78 if(!$uinfo['user'] || !$uinfo['mail']) { 79 msg("$servicename did not provide the needed user info. Can't log you in", -1); 80 return false; 81 } 82 83 // see if the user is known already 84 $user = $this->getUserByEmail($uinfo['mail']); 85 if($user) { 86 $sinfo = $this->getUserData($user); 87 // check if the user allowed access via this service 88 if(!in_array($this->cleanGroup($servicename), $sinfo['grps'])) { 89 msg(sprintf($this->getLang('authnotenabled'), $servicename), -1); 90 return false; 91 } 92 $uinfo['user'] = $user; 93 $uinfo['name'] = $sinfo['name']; 94 $uinfo['grps'] = array_merge((array) $uinfo['grps'], $sinfo['grps']); 95 } else { 96 // new user, create him - making sure the login is unique by adding a number if needed 97 $user = $uinfo['user']; 98 $count = ''; 99 while($this->getUserData($user . $count)) { 100 if($count) { 101 $count++; 102 } else { 103 $count = 1; 104 } 105 } 106 $user = $user . $count; 107 $uinfo['user'] = $user; 108 $groups_on_creation = array(); 109 $groups_on_creation[] = $conf['defaultgroup']; 110 $groups_on_creation[] = $this->cleanGroup($servicename); // add service as group 111 $uinfo['grps'] = array_merge((array) $uinfo['grps'], $groups_on_creation); 112 113 $ok = $this->triggerUserMod('create',array($user, auth_pwgen($user), $uinfo['name'], $uinfo['mail'], 114 $groups_on_creation)); 115 if(!$ok) { 116 msg('something went wrong creating your user account. please try again later.', -1); 117 return false; 118 } 119 120 // send notification about the new user 121 $subscription = new Subscription(); 122 $subscription->send_register($user, $uinfo['name'], $uinfo['mail']); 123 } 124 125 // set user session 126 $this->setUserSession($uinfo, $servicename); 127 128 $cookie = base64_encode($user).'|'.((int) $sticky).'|'.base64_encode('oauth').'|'.base64_encode($servicename); 129 $cookieDir = empty($conf['cookiedir']) ? DOKU_REL : $conf['cookiedir']; 130 $time = $sticky ? (time() + 60 * 60 * 24 * 365) : 0; 131 setcookie(DOKU_COOKIE,$cookie, $time, $cookieDir, '',($conf['securecookie'] && is_ssl()), true); 132 133 if(isset($page)) { 134 send_redirect(wl($page)); 135 } 136 return true; 137 } else { 138 $this->relogin($servicename); 139 } 140 141 unset($_SESSION[DOKU_COOKIE]['auth']); 142 return false; // something went wrong during oAuth login 143 } elseif (isset($_COOKIE[DOKU_COOKIE])) { 144 global $INPUT; 145 //try cookie 146 list($cookieuser, $cookiesticky, $auth, $servicename) = explode('|', $_COOKIE[DOKU_COOKIE]); 147 $cookieuser = base64_decode($cookieuser, true); 148 $auth = base64_decode($auth, true); 149 $servicename = base64_decode($servicename, true); 150 if ($auth === 'oauth') { 151 $this->relogin($servicename); 152 } 153 } 154 155 // do the "normal" plain auth login via form 156 return auth_login($user, $pass, $sticky); 157 } 158 159 protected function relogin($servicename) { 160 global $INPUT; 161 162 /** @var helper_plugin_oauth $hlp */ 163 $hlp = plugin_load('helper', 'oauth'); 164 $service = $hlp->loadService($servicename); 165 if(is_null($service)) return false; 166 167 // remember service in session 168 session_start(); 169 $_SESSION[DOKU_COOKIE]['oauth-inprogress']['service'] = $servicename; 170 $_SESSION[DOKU_COOKIE]['oauth-inprogress']['id'] = $INPUT->str('id'); 171 172 $str_vars = array('wikitext', 'prefix', 'suffix', 'summary', 'sectok', 'target', 'range', 'rev', 'at'); 173 foreach ($str_vars as $input_var) { 174 if ($INPUT->str($input_var) !== '') { 175 $_SESSION[DOKU_COOKIE]['oauth-done'][$input_var] = $INPUT->str($input_var); 176 } 177 178 if ($INPUT->post->str($input_var) !== '') { 179 $_SESSION[DOKU_COOKIE]['oauth-done']['post'][$input_var] = $INPUT->post->str($input_var); 180 } 181 182 if ($INPUT->get->str($input_var) !== '') { 183 $_SESSION[DOKU_COOKIE]['oauth-done']['get'][$input_var] = $INPUT->get->str($input_var); 184 } 185 } 186 187 if (is_array($INPUT->post->param('do'))) { 188 $doPost = key($INPUT->post->arr('do')); 189 } else { 190 $doPost = $INPUT->post->str('do'); 191 } 192 $doGet = $INPUT->get->str('do'); 193 if (!empty($doPost)) { 194 $_SESSION[DOKU_COOKIE]['oauth-done']['do'] = $doPost; 195 } elseif (!empty($doGet)) { 196 $_SESSION[DOKU_COOKIE]['oauth-done']['do'] = $doGet; 197 } 198 199 session_write_close(); 200 201 $service->login(); 202 } 203 204 /** 205 * @param array $data 206 * @param string $service 207 */ 208 protected function setUserSession($data, $service) { 209 global $USERINFO; 210 global $conf; 211 212 // set up groups 213 if(!is_array($data['grps'])) { 214 $data['grps'] = array(); 215 } 216 $data['grps'][] = $this->cleanGroup($service); 217 $data['grps'] = array_unique($data['grps']); 218 219 $USERINFO = $data; 220 $_SERVER['REMOTE_USER'] = $data['user']; 221 $_SESSION[DOKU_COOKIE]['auth']['user'] = $data['user']; 222 $_SESSION[DOKU_COOKIE]['auth']['pass'] = $data['pass']; 223 $_SESSION[DOKU_COOKIE]['auth']['info'] = $USERINFO; 224 $_SESSION[DOKU_COOKIE]['auth']['buid'] = auth_browseruid(); 225 $_SESSION[DOKU_COOKIE]['auth']['time'] = time(); 226 $_SESSION[DOKU_COOKIE]['auth']['oauth'] = $service; 227 } 228 229 /** 230 * Unset additional stuff in session on logout 231 */ 232 public function logOff() { 233 parent::logOff(); 234 235 if(isset($_SESSION[DOKU_COOKIE]['auth']['buid'])) { 236 unset($_SESSION[DOKU_COOKIE]['auth']['buid']); 237 } 238 if(isset($_SESSION[DOKU_COOKIE]['auth']['time'])) { 239 unset($_SESSION[DOKU_COOKIE]['auth']['time']); 240 } 241 if(isset($_SESSION[DOKU_COOKIE]['auth']['oauth'])) { 242 unset($_SESSION[DOKU_COOKIE]['auth']['oauth']); 243 } 244 } 245 246 /** 247 * Find a user by his email address 248 * 249 * @param $mail 250 * @return bool|string 251 */ 252 protected function getUserByEmail($mail) { 253 if($this->users === null) $this->_loadUserData(); 254 $mail = strtolower($mail); 255 256 foreach($this->users as $user => $uinfo) { 257 if(strtolower($uinfo['mail']) == $mail) return $user; 258 } 259 260 return false; 261 } 262 263 /** 264 * Enhance function to check aainst duplicate emails 265 * 266 * @param string $user 267 * @param string $pwd 268 * @param string $name 269 * @param string $mail 270 * @param null $grps 271 * @return bool|null|string 272 */ 273 public function createUser($user, $pwd, $name, $mail, $grps = null) { 274 if($this->getUserByEmail($mail)) { 275 msg($this->getLang('emailduplicate'), -1); 276 return false; 277 } 278 279 return parent::createUser($user, $pwd, $name, $mail, $grps); 280 } 281 282 /** 283 * Enhance function to check aainst duplicate emails 284 * 285 * @param string $user 286 * @param array $changes 287 * @return bool 288 */ 289 public function modifyUser($user, $changes) { 290 global $conf; 291 292 if(isset($changes['mail'])) { 293 $found = $this->getUserByEmail($changes['mail']); 294 if($found != $user) { 295 msg($this->getLang('emailduplicate'), -1); 296 return false; 297 } 298 } 299 300 $ok = parent::modifyUser($user, $changes); 301 302 // refresh session cache 303 touch($conf['cachedir'] . '/sessionpurge'); 304 305 return $ok; 306 } 307 308} 309 310// vim:ts=4:sw=4:et: 311