1<?php 2 3use dokuwiki\Extension\ActionPlugin; 4use dokuwiki\Extension\EventHandler; 5use dokuwiki\Extension\Event; 6use dokuwiki\Form\Form; 7use dokuwiki\plugin\oauth\OAuthManager; 8use OAuth\Common\Http\Exception\TokenResponseException; 9 10/** 11 * DokuWiki Plugin oauth (Action Component) 12 * 13 * This adds buttons to the login page and initializes the oAuth flow by redirecting the user 14 * to the third party service 15 * 16 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 17 * @author Andreas Gohr <andi@splitbrain.org> 18 */ 19class action_plugin_oauth_login extends ActionPlugin 20{ 21 /** @var helper_plugin_oauth */ 22 protected $hlp; 23 24 /** 25 * Constructor 26 * 27 * Initializes the helper 28 */ 29 public function __construct() 30 { 31 $this->hlp = plugin_load('helper', 'oauth'); 32 } 33 34 /** 35 * Registers a callback function for a given event 36 * 37 * @param EventHandler $controller DokuWiki's event controller object 38 * @return void 39 */ 40 public function register(EventHandler $controller) 41 { 42 global $conf; 43 if ($conf['authtype'] != 'oauth') return; 44 45 $conf['profileconfirm'] = false; // password confirmation doesn't work with oauth only users 46 47 $controller->register_hook('DOKUWIKI_STARTED', 'BEFORE', $this, 'handleStart'); 48 $controller->register_hook('HTML_LOGINFORM_OUTPUT', 'BEFORE', $this, 'handleOldLoginForm'); // @deprecated 49 $controller->register_hook('FORM_LOGIN_OUTPUT', 'BEFORE', $this, 'handleLoginForm'); 50 $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'handleDoLogin'); 51 $controller->register_hook('ACTION_DENIED_TPLCONTENT', 'BEFORE', $this, 'handleDeniedForm'); 52 } 53 54 /** 55 * Start an oAuth login or restore environment after successful login 56 * 57 * @param Event $event 58 * @return void 59 */ 60 public function handleStart(Event $event) 61 { 62 global $INPUT; 63 64 // see if a login needs to be started 65 $servicename = $INPUT->str('oauthlogin'); 66 if (!$servicename) return; 67 68 try { 69 $om = new OAuthManager(); 70 $om->startFlow($servicename); 71 } catch (TokenResponseException | Exception $e) { 72 $this->hlp->showException($e, 'login failed'); 73 } 74 } 75 76 /** 77 * Add the oAuth login links to login form 78 * 79 * @param Event $event event object by reference 80 * @return void 81 * @deprecated can be removed in the future 82 */ 83 public function handleOldLoginForm(Event $event) 84 { 85 /** @var Doku_Form $form */ 86 $form = $event->data; 87 $html = $this->prepareLoginButtons(); 88 if (!$html) return; 89 90 // remove login form if single service is set 91 $singleService = $this->getConf('singleService'); 92 if ($singleService) { 93 $form->_content = []; 94 } 95 96 $form->_content[] = form_openfieldset( 97 [ 98 '_legend' => $this->getLang('loginwith'), 99 'class' => 'plugin_oauth', 100 ] 101 ); 102 $form->_content[] = $html; 103 $form->_content[] = form_closefieldset(); 104 } 105 106 /** 107 * Add the oAuth login links to login form 108 * 109 * @param Event $event event object by reference 110 * @return void 111 * @deprecated can be removed in the future 112 */ 113 public function handleLoginForm(Event $event) 114 { 115 /** @var Form $form */ 116 $form = $event->data; 117 $html = $this->prepareLoginButtons(); 118 if (!$html) return; 119 120 // remove login form if single service is set 121 $singleService = $this->getConf('singleService'); 122 if ($singleService) { 123 do { 124 $form->removeElement(0); 125 } while ($form->elementCount() > 0); 126 } 127 128 $form->addFieldsetOpen($this->getLang('loginwith'))->addClass('plugin_oauth'); 129 $form->addHTML($html); 130 $form->addFieldsetClose(); 131 } 132 133 /** 134 * Create HTML for the various login buttons 135 * 136 * @return string the HTML 137 */ 138 protected function prepareLoginButtons() 139 { 140 $html = ''; 141 142 $validDomains = $this->hlp->getValidDomains(); 143 144 if (count($validDomains) > 0) { 145 $html .= '<p class="plugin-oauth-emailrestriction">' . sprintf( 146 $this->getLang('eMailRestricted'), 147 '<b>' . implode(', ', $validDomains) . '</b>' 148 ) . '</p>'; 149 } 150 151 $html .= '<div>'; 152 foreach ($this->hlp->listServices() as $service) { 153 $html .= $service->loginButton(); 154 } 155 $html .= '</div>'; 156 157 return $html; 158 } 159 160 /** 161 * When singleservice is wanted, do not show login, but execute login right away 162 * 163 * @param Event $event 164 * @return bool 165 */ 166 public function handleDoLogin(Event $event) 167 { 168 global $ID; 169 global $INPUT; 170 171 if ($event->data != 'login' && $event->data != 'denied') return true; 172 173 $singleService = $this->getConf('singleService'); 174 if (!$singleService) return true; 175 176 if ($INPUT->server->str('REMOTE_USER') !== '') { 177 // already logged in 178 return true; 179 } 180 181 $enabledServices = $this->hlp->listServices(); 182 if (count($enabledServices) !== 1) { 183 msg($this->getLang('wrongConfig'), -1); 184 return false; 185 } 186 187 $service = array_shift($enabledServices); 188 189 $url = wl($ID, ['oauthlogin' => $service->getServiceID()], true, '&'); 190 send_redirect($url); 191 return true; // never reached 192 } 193 194 /** 195 * Do not show a login form on restricted pages when SingleService is enabled 196 * 197 * This can happen when the user is already logged in, but still doesn't have enough permissions 198 * 199 * @param Event $event 200 * @return void 201 */ 202 public function handleDeniedForm(Event $event) 203 { 204 if ($this->getConf('singleService')) { 205 $event->preventDefault(); 206 $event->stopPropagation(); 207 } 208 } 209} 210