1<?php 2 3use dokuwiki\plugin\oauth\OAuthManager; 4use dokuwiki\plugin\oauth\Session; 5use dokuwiki\Subscriptions\RegistrationSubscriptionSender; 6use OAuth\Common\Exception\Exception as OAuthException; 7 8/** 9 * DokuWiki Plugin oauth (Auth Component) 10 * 11 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 12 * @author Andreas Gohr <andi@splitbrain.org> 13 */ 14class auth_plugin_oauth extends auth_plugin_authplain 15{ 16 /** @var helper_plugin_oauth */ 17 protected $hlp; 18 19 /** @var OAuthManager */ 20 protected $om; 21 22 // region standard auth methods 23 24 /** @inheritDoc */ 25 public function __construct() 26 { 27 parent::__construct(); 28 $this->cando['external'] = true; 29 $this->hlp = $this->loadHelper('oauth'); 30 } 31 32 /** @inheritDoc */ 33 public function trustExternal($user, $pass, $sticky = false) 34 { 35 global $INPUT; 36 37 // handle redirects from farmer to animal wiki instances 38 if ($INPUT->has('state') && plugin_load('helper', 'farmer')) { 39 $this->handleFarmState($INPUT->str('state')); 40 } 41 42 try { 43 // either oauth or "normal" plain auth login via form 44 $this->om = new OAuthManager(); 45 if ($this->om->continueFlow()) return true; 46 if ($this->getConf('singleService')) { 47 return false; // no normal login in singleService mode 48 } 49 return null; // triggers the normal auth_login() 50 } catch (OAuthException $e) { 51 $this->hlp->showException($e); 52 auth_logoff(); // clears all session and cookie data 53 return false; 54 } 55 } 56 57 /** 58 * Enforce oauth login for certain email domains 59 * 60 * @inheritdoc 61 */ 62 public function checkPass($user, $pass) 63 { 64 $ok = parent::checkPass($user, $pass); 65 if(!$ok) return $ok; 66 $domains = $this->hlp->getEnforcedDomains(); 67 if($domains === []) return $ok; 68 69 if($this->hlp->checkMail($this->getUserData($user)['mail'], $domains)) { 70 global $lang; 71 // we overwrite the standard bad password message with our own 72 $lang['badlogin'] = $this->getLang('eMailEnforced'); 73 return false; 74 } 75 return $ok; 76 } 77 78 79 /** 80 * Enhance function to check against duplicate emails 81 * 82 * @inheritdoc 83 */ 84 public function createUser($user, $pwd, $name, $mail, $grps = null) 85 { 86 if ($this->getUserByEmail($mail)) { 87 msg($this->getLang('emailduplicate'), -1); 88 return false; 89 } 90 91 return parent::createUser($user, $pwd, $name, $mail, $grps); 92 } 93 94 /** 95 * Enhance function to check against duplicate emails 96 * 97 * @inheritdoc 98 */ 99 public function modifyUser($user, $changes) 100 { 101 global $conf; 102 103 if (isset($changes['mail'])) { 104 $found = $this->getUserByEmail($changes['mail']); 105 if ($found && $found != $user) { 106 msg($this->getLang('emailduplicate'), -1); 107 return false; 108 } 109 } 110 111 $ok = parent::modifyUser($user, $changes); 112 113 // refresh session cache 114 touch($conf['cachedir'] . '/sessionpurge'); 115 return $ok; 116 } 117 118 /** 119 * Unset additional stuff in session on logout 120 */ 121 public function logOff() 122 { 123 parent::logOff(); 124 if (isset($this->om)) { 125 $this->om->logout(); 126 } 127 (Session::getInstance())->clear(); 128 } 129 130 // endregion 131 132 /** 133 * Register a new user logged in by oauth 134 * 135 * It ensures the username is unique, by adding a number if needed. 136 * Default and service name groups are set here. 137 * Registration notifications are triggered. 138 * 139 * @param array $userinfo This will be updated with the new username 140 * @param string $servicename 141 * 142 * @return bool 143 * @todo - should this be part of the OAuthManager class instead? 144 */ 145 public function registerOAuthUser(&$userinfo, $servicename) 146 { 147 global $conf; 148 $user = $userinfo['user']; 149 $count = ''; 150 while ($this->getUserData($user . $count)) { 151 if ($count) { 152 $count++; 153 } else { 154 $count = 1; 155 } 156 } 157 $user .= $count; 158 $userinfo['user'] = $user; 159 $groups_on_creation = []; 160 $groups_on_creation[] = $conf['defaultgroup']; 161 $groups_on_creation[] = $this->cleanGroup($servicename); // add service as group 162 $userinfo['grps'] = array_merge((array)$userinfo['grps'], $groups_on_creation); 163 164 // the password set here will remain unknown to the user 165 $ok = $this->triggerUserMod( 166 'create', 167 [ 168 $user, 169 auth_pwgen($user), 170 $userinfo['name'], 171 $userinfo['mail'], 172 $userinfo['grps'], 173 ] 174 ); 175 if (!$ok) { 176 return false; 177 } 178 179 // send notification about the new user 180 $subscriptionSender = new RegistrationSubscriptionSender(); 181 $subscriptionSender->sendRegister($user, $userinfo['name'], $userinfo['mail']); 182 183 return true; 184 } 185 186 /** 187 * Find a user by email address 188 * 189 * @param $mail 190 * @return bool|string 191 */ 192 public function getUserByEmail($mail) 193 { 194 if ($this->users === null) { 195 $this->loadUserData(); 196 } 197 $mail = strtolower($mail); 198 199 foreach ($this->users as $user => $userinfo) { 200 if (strtolower($userinfo['mail']) === $mail) return $user; 201 } 202 203 return false; 204 } 205 206 /** 207 * Fall back to plain auth strings 208 * 209 * @inheritdoc 210 */ 211 public function getLang($id) 212 { 213 $result = parent::getLang($id); 214 if ($result) return $result; 215 216 $parent = new auth_plugin_authplain(); 217 return $parent->getLang($id); 218 } 219 220 /** 221 * Farmer plugin support 222 * 223 * When coming back to farmer instance via OAUTH redirectURI, we need to redirect again 224 * to a proper animal instance detected from $state 225 * 226 * @param $state 227 */ 228 protected function handleFarmState($state) 229 { 230 /** @var \helper_plugin_farmer $farmer */ 231 $farmer = plugin_load('helper', 'farmer', false, true); 232 $data = json_decode(base64_decode(urldecode($state))); 233 if (empty($data->animal) || $farmer->getAnimal() == $data->animal) { 234 return; 235 } 236 $animal = $data->animal; 237 $allAnimals = $farmer->getAllAnimals(); 238 if (!in_array($animal, $allAnimals)) { 239 msg('Animal ' . $animal . ' does not exist!'); 240 return; 241 } 242 global $INPUT; 243 $url = $farmer->getAnimalURL($animal) . '/doku.php?' . $INPUT->server->str('QUERY_STRING'); 244 send_redirect($url); 245 } 246} 247