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 } elseif (actionOK('register')) { 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 } else { 124 msg('Self-Registration is currently disabled. Please ask your DokuWiki administrator to create your account manually.', -1); 125 return false; 126 } 127 128 // set user session 129 $this->setUserSession($uinfo, $servicename); 130 131 $cookie = base64_encode($user).'|'.((int) $sticky).'|'.base64_encode('oauth').'|'.base64_encode($servicename); 132 $cookieDir = empty($conf['cookiedir']) ? DOKU_REL : $conf['cookiedir']; 133 $time = $sticky ? (time() + 60 * 60 * 24 * 365) : 0; 134 setcookie(DOKU_COOKIE,$cookie, $time, $cookieDir, '',($conf['securecookie'] && is_ssl()), true); 135 136 if(isset($page)) { 137 send_redirect(wl($page)); 138 } 139 return true; 140 } else { 141 $this->relogin($servicename); 142 } 143 144 unset($_SESSION[DOKU_COOKIE]['auth']); 145 return false; // something went wrong during oAuth login 146 } elseif (isset($_COOKIE[DOKU_COOKIE])) { 147 global $INPUT; 148 //try cookie 149 list($cookieuser, $cookiesticky, $auth, $servicename) = explode('|', $_COOKIE[DOKU_COOKIE]); 150 $cookieuser = base64_decode($cookieuser, true); 151 $auth = base64_decode($auth, true); 152 $servicename = base64_decode($servicename, true); 153 if ($auth === 'oauth') { 154 $this->relogin($servicename); 155 } 156 } 157 158 // do the "normal" plain auth login via form 159 return auth_login($user, $pass, $sticky); 160 } 161 162 protected function relogin($servicename) { 163 global $INPUT; 164 165 /** @var helper_plugin_oauth $hlp */ 166 $hlp = plugin_load('helper', 'oauth'); 167 $service = $hlp->loadService($servicename); 168 if(is_null($service)) return false; 169 170 // remember service in session 171 session_start(); 172 $_SESSION[DOKU_COOKIE]['oauth-inprogress']['service'] = $servicename; 173 $_SESSION[DOKU_COOKIE]['oauth-inprogress']['id'] = $INPUT->str('id'); 174 175 $str_vars = array('wikitext', 'prefix', 'suffix', 'summary', 'sectok', 'target', 'range', 'rev', 'at'); 176 foreach ($str_vars as $input_var) { 177 if ($INPUT->str($input_var) !== '') { 178 $_SESSION[DOKU_COOKIE]['oauth-done'][$input_var] = $INPUT->str($input_var); 179 } 180 181 if ($INPUT->post->str($input_var) !== '') { 182 $_SESSION[DOKU_COOKIE]['oauth-done']['post'][$input_var] = $INPUT->post->str($input_var); 183 } 184 185 if ($INPUT->get->str($input_var) !== '') { 186 $_SESSION[DOKU_COOKIE]['oauth-done']['get'][$input_var] = $INPUT->get->str($input_var); 187 } 188 } 189 190 if (is_array($INPUT->post->param('do'))) { 191 $doPost = key($INPUT->post->arr('do')); 192 } else { 193 $doPost = $INPUT->post->str('do'); 194 } 195 $doGet = $INPUT->get->str('do'); 196 if (!empty($doPost)) { 197 $_SESSION[DOKU_COOKIE]['oauth-done']['do'] = $doPost; 198 } elseif (!empty($doGet)) { 199 $_SESSION[DOKU_COOKIE]['oauth-done']['do'] = $doGet; 200 } 201 202 session_write_close(); 203 204 $service->login(); 205 } 206 207 /** 208 * @param array $data 209 * @param string $service 210 */ 211 protected function setUserSession($data, $service) { 212 global $USERINFO; 213 global $conf; 214 215 // set up groups 216 if(!is_array($data['grps'])) { 217 $data['grps'] = array(); 218 } 219 $data['grps'][] = $this->cleanGroup($service); 220 $data['grps'] = array_unique($data['grps']); 221 222 $USERINFO = $data; 223 $_SERVER['REMOTE_USER'] = $data['user']; 224 $_SESSION[DOKU_COOKIE]['auth']['user'] = $data['user']; 225 $_SESSION[DOKU_COOKIE]['auth']['pass'] = $data['pass']; 226 $_SESSION[DOKU_COOKIE]['auth']['info'] = $USERINFO; 227 $_SESSION[DOKU_COOKIE]['auth']['buid'] = auth_browseruid(); 228 $_SESSION[DOKU_COOKIE]['auth']['time'] = time(); 229 $_SESSION[DOKU_COOKIE]['auth']['oauth'] = $service; 230 } 231 232 /** 233 * Unset additional stuff in session on logout 234 */ 235 public function logOff() { 236 parent::logOff(); 237 238 if(isset($_SESSION[DOKU_COOKIE]['auth']['buid'])) { 239 unset($_SESSION[DOKU_COOKIE]['auth']['buid']); 240 } 241 if(isset($_SESSION[DOKU_COOKIE]['auth']['time'])) { 242 unset($_SESSION[DOKU_COOKIE]['auth']['time']); 243 } 244 if(isset($_SESSION[DOKU_COOKIE]['auth']['oauth'])) { 245 unset($_SESSION[DOKU_COOKIE]['auth']['oauth']); 246 } 247 } 248 249 /** 250 * Find a user by his email address 251 * 252 * @param $mail 253 * @return bool|string 254 */ 255 protected function getUserByEmail($mail) { 256 if($this->users === null) $this->_loadUserData(); 257 $mail = strtolower($mail); 258 259 foreach($this->users as $user => $uinfo) { 260 if(strtolower($uinfo['mail']) == $mail) return $user; 261 } 262 263 return false; 264 } 265 266 /** 267 * Enhance function to check aainst duplicate emails 268 * 269 * @param string $user 270 * @param string $pwd 271 * @param string $name 272 * @param string $mail 273 * @param null $grps 274 * @return bool|null|string 275 */ 276 public function createUser($user, $pwd, $name, $mail, $grps = null) { 277 if($this->getUserByEmail($mail)) { 278 msg($this->getLang('emailduplicate'), -1); 279 return false; 280 } 281 282 return parent::createUser($user, $pwd, $name, $mail, $grps); 283 } 284 285 /** 286 * Enhance function to check aainst duplicate emails 287 * 288 * @param string $user 289 * @param array $changes 290 * @return bool 291 */ 292 public function modifyUser($user, $changes) { 293 global $conf; 294 295 if(isset($changes['mail'])) { 296 $found = $this->getUserByEmail($changes['mail']); 297 if($found != $user) { 298 msg($this->getLang('emailduplicate'), -1); 299 return false; 300 } 301 } 302 303 $ok = parent::modifyUser($user, $changes); 304 305 // refresh session cache 306 touch($conf['cachedir'] . '/sessionpurge'); 307 308 return $ok; 309 } 310 311} 312 313// vim:ts=4:sw=4:et: 314