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