1<?php 2 3namespace dokuwiki\plugin\oauth; 4 5use OAuth\Common\Http\Exception\TokenResponseException; 6 7class OAuthManager 8{ 9 10 /** 11 * @throws Exception 12 * @throws TokenResponseException 13 */ 14 public function startFlow($servicename) 15 { 16 // generate a new GUID to identify this user 17 $guid = bin2hex(random_bytes(16)); 18 19 $session = Session::getInstance(); 20 $session->setLoginData($servicename, $guid); 21 22 // fixme store environment 23 $service = $this->loadService($servicename); 24 $service->initOAuthService($guid); 25 $service->login(); // redirects 26 27 } 28 29 /** 30 * @return bool true if the login has been handled 31 * @throws Exception 32 * @throws \OAuth\Common\Exception\Exception 33 * @todo this probably moves over to auth 34 */ 35 public function continueFlow() 36 { 37 38 return $this->loginByService() or 39 $this->loginBySession() or 40 $this->loginByCookie(); 41 42 } 43 44 /** 45 * @return bool true if successful, false if not applies, 46 * @throws \OAuth\Common\Exception\Exception 47 * @throws Exception 48 */ 49 protected function loginByService() 50 { 51 global $INPUT; 52 53 if (!$INPUT->get->has('code') && !$INPUT->get->has('oauth_token')) { 54 return false; 55 } 56 57 $session = Session::getInstance(); 58 59 // init service from session 60 $logindata = $session->getLoginData(); 61 if (!$logindata) return false; 62 $service = $this->loadService($logindata['servicename']); 63 $service->initOAuthService($logindata['guid']); 64 $session->clearLoginData(); 65 66 // oAuth login 67 if (!$service->checkToken()) throw new Exception("Login failed"); 68 $userdata = $service->getUser(); 69 70 // processing 71 $userdata = $this->validateUserData($userdata, $logindata['servicename']); 72 $userdata = $this->processUserData($userdata, $logindata['servicename']); 73 74 // login 75 $session->setUser($userdata); // log in 76 $session->setCookie($logindata['servicename'], $logindata['guid']); // set cookie 77 78 // fixme restore environment 79 80 return true; 81 } 82 83 /** 84 * Login a user based on their current session data 85 * 86 * This will also log in plainauth users 87 * 88 * @return bool true if successful, false if not applies, 89 * @throws Exception 90 */ 91 protected function loginBySession() 92 { 93 $session = Session::getInstance(); 94 if (!$session->isValid()) { 95 $session->clear(); 96 return false; 97 } 98 99 $userdata = $session->getUser(); 100 $session->setUser($userdata, false); // does a login without resetting the time 101 102 return true; 103 } 104 105 /** 106 * Login a user based on their cookie and a previously saved access token 107 * 108 * @return bool true if successful, false if not applies, 109 * @throws Exception 110 */ 111 protected function loginByCookie() 112 { 113 $session = Session::getInstance(); 114 $cookie = $session->getCookie(); 115 if (!$cookie) return false; 116 117 try { 118 $service = $this->loadService($cookie['servicename']); 119 $service->initOAuthService($cookie['guid']); 120 } catch (Exception $e) { 121 return false; // maybe cookie had old service that is no longer available 122 } 123 124 $userdata = $service->getUser(); // this should use a previously saved token 125 $session->setUser($userdata); // log in 126 return true; 127 } 128 129 /** 130 * Clean and validate the user data provided from the service 131 * 132 * @param array $userdata 133 * @param string $servicename 134 * @return array 135 * @throws Exception 136 * @todo test 137 */ 138 protected function validateUserData($userdata, $servicename) 139 { 140 /** @var \auth_plugin_oauth */ 141 global $auth; 142 143 // mail is required 144 if (empty($userdata['mail'])) { 145 throw new Exception("$servicename did not provide the an email address. Can't log you in"); 146 } 147 148 // mail needs to be allowed 149 /** @var \helper_plugin_oauth $hlp */ 150 $hlp = plugin_load('helper', 'oauth'); 151 $hlp->checkMail($userdata['mail']); 152 153 // make username from mail if empty 154 $userdata['user'] = $auth->cleanUser((string)$userdata['user']); 155 if ($userdata === '') { 156 list($userdata['user']) = explode('@', $userdata['mail']); 157 } 158 159 // make full name from username if empty 160 if (empty($userdata['name'])) { 161 $userdata['name'] = $userdata['user']; 162 } 163 164 return $userdata; 165 } 166 167 /** 168 * Process the userdata, update the user info array and create the user if necessary 169 * 170 * Uses the global $auth object for user management 171 * 172 * @param array $userdata User info received from authentication 173 * @param string $servicename Auth service 174 * @return array the modified user info 175 * @throws Exception 176 */ 177 protected function processUserData($userdata, $servicename) 178 { 179 /** @var \auth_plugin_oauth */ 180 global $auth; 181 182 // see if the user is known already 183 $localUser = $auth->getUserByEmail($userdata['mail']); 184 if ($localUser) { 185 $localUserInfo = $auth->getUserData($localUser); 186 // check if the user allowed access via this service 187 if (!in_array($auth->cleanGroup($servicename), $localUserInfo['grps'])) { 188 throw new Exception(sprintf($auth->getLang('authnotenabled'), $servicename)); 189 } 190 $userdata['user'] = $localUser; 191 $userdata['name'] = $localUserInfo['name']; 192 $userdata['grps'] = array_merge((array)$userdata['grps'], $localUserInfo['grps']); 193 } elseif (actionOK('register') || $auth->getConf('register-on-auth')) { 194 if (!$auth->addUser($userdata, $servicename)) { 195 throw new Exception('something went wrong creating your user account. please try again later.'); 196 } 197 } else { 198 throw new Exception($auth->getLang('addUser not possible')); 199 } 200 201 return $userdata; 202 } 203 204 /** 205 * Instantiates a Service by name 206 * 207 * @param string $servicename 208 * @return Service 209 * @throws Exception 210 */ 211 protected function loadService($servicename) 212 { 213 /** @var \helper_plugin_oauth $hlp */ 214 $hlp = plugin_load('helper', 'oauth'); 215 $srv = $hlp->loadService($servicename); 216 217 if ($srv === null) throw new Exception("No such service $servicename"); 218 return $srv; 219 } 220 221} 222