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 return $this->om->continueFlow() || auth_login($user, $pass, $sticky); 46 } catch (OAuthException $e) { 47 $this->hlp->showException($e); 48 auth_logoff(); // clears all session and cookie data 49 return false; 50 } 51 } 52 53 /** 54 * Enhance function to check against duplicate emails 55 * 56 * @inheritdoc 57 */ 58 public function createUser($user, $pwd, $name, $mail, $grps = null) 59 { 60 if ($this->getUserByEmail($mail)) { 61 msg($this->getLang('emailduplicate'), -1); 62 return false; 63 } 64 65 return parent::createUser($user, $pwd, $name, $mail, $grps); 66 } 67 68 /** 69 * Enhance function to check against duplicate emails 70 * 71 * @inheritdoc 72 */ 73 public function modifyUser($user, $changes) 74 { 75 global $conf; 76 77 if (isset($changes['mail'])) { 78 $found = $this->getUserByEmail($changes['mail']); 79 if ($found && $found != $user) { 80 msg($this->getLang('emailduplicate'), -1); 81 return false; 82 } 83 } 84 85 $ok = parent::modifyUser($user, $changes); 86 87 // refresh session cache 88 touch($conf['cachedir'] . '/sessionpurge'); 89 return $ok; 90 } 91 92 /** 93 * Unset additional stuff in session on logout 94 */ 95 public function logOff() 96 { 97 parent::logOff(); 98 if (isset($this->om)) { 99 $this->om->logout(); 100 } 101 (Session::getInstance())->clear(); 102 } 103 104 // endregion 105 106 /** 107 * Register a new user logged in by oauth 108 * 109 * It ensures the username is unique, by adding a number if needed. 110 * Default and service name groups are set here. 111 * Registration notifications are triggered. 112 * 113 * @param array $userinfo This will be updated with the new username 114 * @param string $servicename 115 * 116 * @return bool 117 * @todo - should this be part of the OAuthManager class instead? 118 */ 119 public function registerOAuthUser(&$userinfo, $servicename) 120 { 121 global $conf; 122 $user = $userinfo['user']; 123 $count = ''; 124 while ($this->getUserData($user . $count)) { 125 if ($count) { 126 $count++; 127 } else { 128 $count = 1; 129 } 130 } 131 $user = $user . $count; 132 $userinfo['user'] = $user; 133 $groups_on_creation = []; 134 $groups_on_creation[] = $conf['defaultgroup']; 135 $groups_on_creation[] = $this->cleanGroup($servicename); // add service as group 136 $userinfo['grps'] = array_merge((array)$userinfo['grps'], $groups_on_creation); 137 138 // the password set here will remain unknown to the user 139 $ok = $this->triggerUserMod( 140 'create', 141 [ 142 $user, 143 auth_pwgen($user), 144 $userinfo['name'], 145 $userinfo['mail'], 146 $userinfo['grps'], 147 ] 148 ); 149 if (!$ok) { 150 return false; 151 } 152 153 // send notification about the new user 154 $subscriptionSender = new RegistrationSubscriptionSender(); 155 $subscriptionSender->sendRegister($user, $userinfo['name'], $userinfo['mail']); 156 157 return true; 158 } 159 160 /** 161 * Find a user by email address 162 * 163 * @param $mail 164 * @return bool|string 165 */ 166 public function getUserByEmail($mail) 167 { 168 if ($this->users === null) { 169 $this->loadUserData(); 170 } 171 $mail = strtolower($mail); 172 173 foreach ($this->users as $user => $userinfo) { 174 if (strtolower($userinfo['mail']) == $mail) return $user; 175 } 176 177 return false; 178 } 179 180 /** 181 * Fall back to plain auth strings 182 * 183 * @inheritdoc 184 */ 185 public function getLang($id) 186 { 187 $result = parent::getLang($id); 188 if($result) return $result; 189 190 $parent = new auth_plugin_authplain(); 191 return $parent->getLang($id); 192 } 193 194 /** 195 * Farmer plugin support 196 * 197 * When coming back to farmer instance via OAUTH redirectURI, we need to redirect again 198 * to a proper animal instance detected from $state 199 * 200 * @param $state 201 */ 202 protected function handleFarmState($state) 203 { 204 /** @var \helper_plugin_farmer $farmer */ 205 $farmer = plugin_load('helper', 'farmer', false, true); 206 $data = json_decode(base64_decode(urldecode($state))); 207 if (empty($data->animal) || $farmer->getAnimal() == $data->animal) { 208 return; 209 } 210 $animal = $data->animal; 211 $allAnimals = $farmer->getAllAnimals(); 212 if (!in_array($animal, $allAnimals)) { 213 msg('Animal ' . $animal . ' does not exist!'); 214 return; 215 } 216 global $INPUT; 217 $url = $farmer->getAnimalURL($animal) . '/doku.php?' . $INPUT->server->str('QUERY_STRING'); 218 send_redirect($url); 219 } 220} 221