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