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