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 $INPUT; 38 global $conf; 39 global $USERINFO; 40 41 $servicename = $INPUT->str('oa'); 42 43 // check session for existing oAuth login data 44 $session = $_SESSION[DOKU_COOKIE]['auth']; 45 if(!$servicename && isset($session['oauth'])) { 46 $servicename = $session['oauth']; 47 // check if session data is still considered valid 48 if(($session['time'] >= time() - $conf['auth_security_timeout']) && 49 ($session['buid'] == auth_browseruid()) 50 ) { 51 52 $_SERVER['REMOTE_USER'] = $session['user']; 53 $USERINFO = $session['info']; 54 return true; 55 } 56 } 57 58 // either we're in oauth login or a previous log needs to be rechecked 59 if($servicename) { 60 /** @var helper_plugin_oauth $hlp */ 61 $hlp = plugin_load('helper', 'oauth'); 62 $service = $hlp->loadService($servicename); 63 if(is_null($service)) return false; 64 65 // get the token 66 if($service->checkToken()) { 67 $uinfo = $service->getUser(); 68 69 $uinfo['user'] = $this->cleanUser((string) $uinfo['user']); 70 if(!$uinfo['name']) $uinfo['name'] = $uinfo['user']; 71 72 if(!$uinfo['user'] || !$uinfo['mail']) { 73 msg("$servicename did not provide the needed user info. Can't log you in", -1); 74 return false; 75 } 76 77 // see if the user is known already 78 $user = $this->getUserByEmail($uinfo['mail']); 79 if($user) { 80 $sinfo = $this->getUserData($user); 81 // check if the user allowed access via this service 82 if(!in_array($this->cleanGroup($servicename), $sinfo['grps'])) { 83 msg(sprintf($this->getLang('authnotenabled'), $servicename), -1); 84 return false; 85 } 86 $uinfo['user'] = $user; 87 $uinfo['name'] = $sinfo['name']; 88 $uinfo['grps'] = array_merge((array) $uinfo['grps'], $sinfo['grps']); 89 } else { 90 // new user, create him - making sure the login is unique by adding a number if needed 91 $user = $uinfo['user']; 92 $count = ''; 93 while($this->getUserData($user.$count)) { 94 if($count) { 95 $count++; 96 } else { 97 $count = 1; 98 } 99 } 100 $user = $user.$count; 101 $uinfo['user'] = $user; 102 $uinfo['grps'] = (array) $uinfo['grps']; 103 $uinfo['grps'][] = $conf['defaultgroup']; 104 $uinfo['grps'][] = $this->cleanGroup($servicename); // add service as group 105 106 //FIXME we should call trigger_user_mod? 107 $ok = $this->createUser($user, auth_pwgen($user), $uinfo['name'], $uinfo['mail'], $uinfo['grps']); 108 if(!$ok) { 109 msg('something went wrong creating your user account. please try again later.', -1); 110 return false; 111 } 112 113 // send notification about the new user 114 $subscription = new Subscription(); 115 $subscription->send_register($user, $uinfo['name'], $uinfo['mail']); 116 } 117 118 // set user session 119 $this->setUserSession($uinfo, $servicename); 120 return true; 121 } 122 123 return false; // something went wrong during oAuth login 124 } 125 126 // do the "normal" plain auth login via form 127 return auth_login($user, $pass, $sticky); 128 } 129 130 /** 131 * @param array $data 132 * @param string $service 133 */ 134 protected function setUserSession($data, $service) { 135 global $USERINFO; 136 global $conf; 137 138 // set up groups 139 if(!is_array($data['grps'])) { 140 $data['grps'] = array(); 141 } 142 $data['grps'][] = $this->cleanGroup($service); 143 $data['grps'] = array_unique($data['grps']); 144 145 $USERINFO = $data; 146 $_SERVER['REMOTE_USER'] = $data['user']; 147 $_SESSION[DOKU_COOKIE]['auth']['user'] = $data['user']; 148 $_SESSION[DOKU_COOKIE]['auth']['pass'] = $data['pass']; 149 $_SESSION[DOKU_COOKIE]['auth']['info'] = $USERINFO; 150 $_SESSION[DOKU_COOKIE]['auth']['buid'] = auth_browseruid(); 151 $_SESSION[DOKU_COOKIE]['auth']['time'] = time(); 152 $_SESSION[DOKU_COOKIE]['auth']['oauth'] = $service; 153 } 154 155 /** 156 * Unset additional stuff in session on logout 157 */ 158 public function logOff() { 159 parent::logOff(); 160 161 if(isset($_SESSION[DOKU_COOKIE]['auth']['buid'])) { 162 unset($_SESSION[DOKU_COOKIE]['auth']['buid']); 163 } 164 if(isset($_SESSION[DOKU_COOKIE]['auth']['time'])) { 165 unset($_SESSION[DOKU_COOKIE]['auth']['time']); 166 } 167 if(isset($_SESSION[DOKU_COOKIE]['auth']['oauth'])) { 168 unset($_SESSION[DOKU_COOKIE]['auth']['oauth']); 169 } 170 } 171 172 /** 173 * Find a user by his email address 174 * 175 * @param $mail 176 * @return bool|string 177 */ 178 protected function getUserByEmail($mail) { 179 if($this->users === null) $this->_loadUserData(); 180 $mail = strtolower($mail); 181 182 foreach($this->users as $user => $uinfo) { 183 if(strtolower($uinfo['mail']) == $mail) return $user; 184 } 185 186 return false; 187 } 188 189 /** 190 * Enhance function to check aainst duplicate emails 191 * 192 * @param string $user 193 * @param string $pwd 194 * @param string $name 195 * @param string $mail 196 * @param null $grps 197 * @return bool|null|string 198 */ 199 public function createUser($user, $pwd, $name, $mail, $grps = null) { 200 if($this->getUserByEmail($mail)) { 201 msg($this->getLang('emailduplicate'), -1); 202 return false; 203 } 204 205 return parent::createUser($user, $pwd, $name, $mail, $grps); 206 } 207 208 /** 209 * Enhance function to check aainst duplicate emails 210 * 211 * @param string $user 212 * @param array $changes 213 * @return bool 214 */ 215 public function modifyUser($user, $changes) { 216 global $conf; 217 218 if(isset($changes['mail'])) { 219 $found = $this->getUserByEmail($changes['mail']); 220 if($found != $user) { 221 msg($this->getLang('emailduplicate'), -1); 222 return false; 223 } 224 } 225 226 $ok = parent::modifyUser($user, $changes); 227 228 // refresh session cache 229 touch($conf['cachedir'].'/sessionpurge'); 230 231 return $ok; 232 } 233 234} 235 236// vim:ts=4:sw=4:et: