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