1<?php 2 3use dokuwiki\Form\Form; 4use dokuwiki\plugin\oauth\SessionManager; 5use OAuth\Common\Http\Exception\TokenResponseException; 6 7/** 8 * DokuWiki Plugin oauth (Action Component) 9 * 10 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 11 * @author Andreas Gohr <andi@splitbrain.org> 12 */ 13class action_plugin_oauth_login extends DokuWiki_Action_Plugin 14{ 15 /** @var helper_plugin_oauth */ 16 protected $hlp; 17 18 /** 19 * Constructor 20 * 21 * Initializes the helper 22 */ 23 public function __construct() 24 { 25 $this->hlp = plugin_load('helper', 'oauth'); 26 } 27 28 /** 29 * Registers a callback function for a given event 30 * 31 * @param Doku_Event_Handler $controller DokuWiki's event controller object 32 * @return void 33 */ 34 public function register(Doku_Event_Handler $controller) 35 { 36 global $conf; 37 if ($conf['authtype'] != 'oauth') return; 38 39 $conf['profileconfirm'] = false; // password confirmation doesn't work with oauth only users 40 41 $controller->register_hook('DOKUWIKI_STARTED', 'BEFORE', $this, 'handleStart'); 42 $controller->register_hook('HTML_LOGINFORM_OUTPUT', 'BEFORE', $this, 'handleOldLoginForm'); // @deprecated 43 $controller->register_hook('FORM_LOGIN_OUTPUT', 'BEFORE', $this, 'handleLoginForm'); 44 $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'handleDoLogin'); 45 } 46 47 /** 48 * Start an oAuth login or restore environment after successful login 49 * 50 * @param Doku_Event $event 51 * @return void 52 */ 53 public function handleStart(Doku_Event $event) 54 { 55 global $INPUT; 56 57 // login has been done, but there's environment to be restored 58 // TODO when is this the case? 59 $sessionManager = SessionManager::getInstance(); 60 if ($sessionManager->getDo() || $sessionManager->getRev()) { 61 $this->restoreSessionEnvironment(); 62 return; 63 } 64 65 // see if a login needs to be started 66 $servicename = $INPUT->str('oauthlogin'); 67 if ($servicename) $this->startOAuthLogin($servicename); 68 } 69 70 /** 71 * Add the oAuth login links to login form 72 * 73 * @param Doku_Event $event event object by reference 74 * @deprecated can be removed in the future 75 * @return void 76 */ 77 public function handleOldLoginForm(Doku_Event $event) 78 { 79 /** @var Doku_Form $form */ 80 $form = $event->data; 81 $html = $this->prepareLoginButtons(); 82 if (!$html) return; 83 84 $form->_content[] = form_openfieldset( 85 [ 86 '_legend' => $this->getLang('loginwith'), 87 'class' => 'plugin_oauth', 88 ] 89 ); 90 $form->_content[] = $html; 91 $form->_content[] = form_closefieldset(); 92 } 93 94 95 /** 96 * Add the oAuth login links to login form 97 * 98 * @param Doku_Event $event event object by reference 99 * @deprecated can be removed in the future 100 * @return void 101 */ 102 public function handleLoginForm(Doku_Event $event) 103 { 104 /** @var Form $form */ 105 $form = $event->data; 106 $html = $this->prepareLoginButtons(); 107 if (!$html) return; 108 109 $form->addFieldsetOpen($this->getLang('loginwith'))->addClass('plugin_oauth'); 110 $form->addHTML($html); 111 $form->addFieldsetClose(); 112 } 113 114 /** 115 * Create HTML for the various login buttons 116 * 117 * @return string the HTML 118 */ 119 protected function prepareLoginButtons() { 120 $html = ''; 121 122 $validDomains = $this->hlp->getValidDomains(); 123 124 if (count($validDomains) > 0) { 125 $html .= sprintf($this->getLang('eMailRestricted'), join(', ', $validDomains)); 126 } 127 128 foreach ($this->hlp->listServices() as $service) { 129 $html .= $service->loginButton(); 130 } 131 132 return $html; 133 } 134 135 /** 136 * When singleservice is wanted, do not show login, but execute login right away 137 * 138 * @param Doku_Event $event 139 * @return bool 140 */ 141 public function handleDoLogin(Doku_Event $event) 142 { 143 global $ID; 144 145 if ($event->data != 'login') return true; 146 147 $singleService = $this->getConf('singleService'); 148 if (!$singleService) return true; 149 150 $enabledServices = $this->hlp->listServices(); 151 if (count($enabledServices) !== 1) { 152 msg($this->getLang('wrongConfig'), -1); 153 return false; 154 } 155 156 $service = array_shift($enabledServices); 157 158 $url = wl($ID, ['oauthlogin' => $service->getServiceID()], true, '&'); 159 send_redirect($url); 160 return true; // never reached 161 } 162 163 /** 164 * start the oauth login 165 * 166 * This will redirect to the external service and stop processing in this request. 167 * The second part of the login will happen in auth 168 * 169 * @see auth_plugin_oauth 170 */ 171 protected function startOAuthLogin($servicename) 172 { 173 global $ID; 174 $service = $this->hlp->loadService($servicename); 175 if (is_null($service)) return; 176 177 // remember service in session 178 $sessionManager = SessionManager::getInstance(); 179 $sessionManager->setServiceName($servicename); 180 $sessionManager->setPid($ID); 181 $sessionManager->saveState(); 182 183 try { 184 $service->login(); // redirects 185 } catch (TokenResponseException $e) { 186 $this->hlp->showException($e, 'login failed'); 187 } 188 } 189 190 /** 191 * Restore the request environment that had been set before the oauth shuffle 192 */ 193 protected function restoreSessionEnvironment() 194 { 195 global $INPUT, $ACT, $TEXT, $PRE, $SUF, $SUM, $RANGE, $DATE_AT, $REV; 196 197 $sessionManager = SessionManager::getInstance(); 198 $ACT = $sessionManager->getDo(); 199 $_REQUEST = $sessionManager->getRequest(); 200 201 $REV = $INPUT->int('rev'); 202 $DATE_AT = $INPUT->str('at'); 203 $RANGE = $INPUT->str('range'); 204 if ($INPUT->post->has('wikitext')) { 205 $TEXT = cleanText($INPUT->post->str('wikitext')); 206 } 207 $PRE = cleanText(substr($INPUT->post->str('prefix'), 0, -1)); 208 $SUF = cleanText($INPUT->post->str('suffix')); 209 $SUM = $INPUT->post->str('summary'); 210 211 $sessionManager->setDo(''); 212 $sessionManager->setRequest([]); 213 $sessionManager->saveState(); 214 } 215} 216