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 //FIXME we should send a notification 108 $this->createUser($user, auth_pwgen($user), $uinfo['name'], $uinfo['mail'], $uinfo['grps']); 109 } 110 111 // set user session 112 $this->setUserSession($uinfo, $servicename); 113 return true; 114 } 115 116 return false; // something went wrong during oAuth login 117 } 118 119 // do the "normal" plain auth login via form 120 return auth_login($user, $pass, $sticky); 121 } 122 123 /** 124 * @param array $data 125 * @param string $service 126 */ 127 protected function setUserSession($data, $service) { 128 global $USERINFO; 129 global $conf; 130 131 // set up groups 132 if(!is_array($data['grps'])) { 133 $data['grps'] = array(); 134 } 135 $data['grps'][] = $this->cleanGroup($service); 136 $data['grps'] = array_unique($data['grps']); 137 138 $USERINFO = $data; 139 $_SERVER['REMOTE_USER'] = $data['user']; 140 $_SESSION[DOKU_COOKIE]['auth']['user'] = $data['user']; 141 $_SESSION[DOKU_COOKIE]['auth']['pass'] = $data['pass']; 142 $_SESSION[DOKU_COOKIE]['auth']['info'] = $USERINFO; 143 $_SESSION[DOKU_COOKIE]['auth']['buid'] = auth_browseruid(); 144 $_SESSION[DOKU_COOKIE]['auth']['time'] = time(); 145 $_SESSION[DOKU_COOKIE]['auth']['oauth'] = $service; 146 } 147 148 /** 149 * Unset additional stuff in session on logout 150 */ 151 public function logOff() { 152 parent::logOff(); 153 154 if(isset($_SESSION[DOKU_COOKIE]['auth']['buid'])) { 155 unset($_SESSION[DOKU_COOKIE]['auth']['buid']); 156 } 157 if(isset($_SESSION[DOKU_COOKIE]['auth']['time'])) { 158 unset($_SESSION[DOKU_COOKIE]['auth']['time']); 159 } 160 if(isset($_SESSION[DOKU_COOKIE]['auth']['oauth'])) { 161 unset($_SESSION[DOKU_COOKIE]['auth']['oauth']); 162 } 163 } 164 165 /** 166 * Find a user by his email address 167 * 168 * @param $mail 169 * @return bool|string 170 */ 171 protected function getUserByEmail($mail) { 172 if($this->users === null) $this->_loadUserData(); 173 $mail = strtolower($mail); 174 175 foreach($this->users as $user => $uinfo) { 176 if(strtolower($uinfo['mail']) == $mail) return $user; 177 } 178 179 return false; 180 } 181 182 /** 183 * Enhance function to check aainst duplicate emails 184 * 185 * @param string $user 186 * @param string $pwd 187 * @param string $name 188 * @param string $mail 189 * @param null $grps 190 * @return bool|null|string 191 */ 192 public function createUser($user, $pwd, $name, $mail, $grps = null) { 193 if($this->getUserByEmail($mail)) { 194 msg($this->getLang('emailduplicate'), -1); 195 return false; 196 } 197 198 return parent::createUser($user, $pwd, $name, $mail, $grps); 199 } 200 201 /** 202 * Enhance function to check aainst duplicate emails 203 * 204 * @param string $user 205 * @param array $changes 206 * @return bool 207 */ 208 public function modifyUser($user, $changes) { 209 global $conf; 210 211 if(isset($changes['mail'])) { 212 $found = $this->getUserByEmail($changes['mail']); 213 if($found != $user) { 214 msg($this->getLang('emailduplicate'), -1); 215 return false; 216 } 217 } 218 219 $ok = parent::modifyUser($user, $changes); 220 221 // refresh session cache 222 touch($conf['cachedir'].'/sessionpurge'); 223 224 return $ok; 225 } 226 227} 228 229// vim:ts=4:sw=4:et: