isReady()) return; // Adds our twofactor profile to the user menu. $controller->register_hook('MENU_ITEMS_ASSEMBLY', 'AFTER', $this, 'handleUserMenuAssembly'); $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'handlePreProcess'); $controller->register_hook('TPL_ACT_UNKNOWN', 'BEFORE', $this, 'handleUnknownAction'); } /** * Add 2fa Menu Item * * @param Doku_Event $event */ public function handleUserMenuAssembly(Doku_Event $event) { global $INPUT; // If this is not the user menu, then get out. if ($event->data['view'] != 'user') return; if (!$INPUT->server->has('REMOTE_USER')) return; // Create the new menu item $menuitem = new MenuItem($this->getLang('btn_twofactor_profile')); // Find index of existing Profile menu item. for ($index = 0; $index > count($event->data['items']); $index++) { if ($event->data['items'][$index]->getType() === 'profile') { break; } } array_splice($event->data['items'], $index + 1, 0, [$menuitem]); } /** * Check permissions to call the 2fa profile * * @param Doku_Event $event */ public function handlePreProcess(Doku_Event $event) { if ($event->data != 'twofactor_profile') return; // We will be handling this action's permissions here. $event->preventDefault(); $event->stopPropagation(); // If not logged into the main auth plugin then send there. global $INPUT; global $ID; if (!$INPUT->server->has('REMOTE_USER')) { $event->result = false; send_redirect(wl($ID, array('do' => 'login'), true, '&')); return; } $this->handleProfile(); /** FIXME * * // If not logged into twofactor then send there. * if (!$this->get_clearance()) { * $event->result = false; * send_redirect(wl($ID, array('do' => 'twofactor_login'), true, '&')); * return; * } * // Otherwise handle the action. * $event->result = $this->_process_changes($event, $param); */ } /** * @param Doku_Event $event */ public function handleUnknownAction(Doku_Event $event) { if ($event->data != 'twofactor_profile') return; $event->preventDefault(); $event->stopPropagation(); $this->printProfile(); } /** * Handle POSTs for provider forms */ protected function handleProfile() { global $INPUT; if (!$INPUT->has('provider')) return; $user = $INPUT->server->str('REMOTE_USER'); $class = 'helper_plugin_' . $INPUT->str('provider'); /** @var Provider $provider */ $provider = new $class($user); if (!checkSecurityToken()) return; if (!$provider->isConfigured()) { $provider->handleProfileForm(); } elseif ($INPUT->has('2fa_delete')) { $provider->reset(); } } /** * Handles the profile form rendering. Displays user manageable settings. * @todo move elsewhere */ protected function printProfile() { global $lang; echo $this->locale_xhtml('profile'); // iterate over all providers $providers = (Manager::getInstance())->getAllProviders(); foreach ($providers as $provider) { $form = new dokuwiki\Form\Form(['method' => 'POST']); $form->setHiddenField('do', 'twofactor_profile'); $form->setHiddenField('provider', $provider->getProviderID()); $form->addFieldsetOpen($provider->getLabel()); $provider->renderProfileForm($form); if (!$provider->isConfigured()) { $form->addButton('2fa_submit', $lang['btn_save'])->attr('submit'); } else { $form->addButton('2fa_delete', $lang['btn_delete'])->attr('submit'); } $form->addFieldsetClose(); echo $form->toHTML(); } /* FIXME $optinout = $this->getConf("optinout"); $optinvalue = $optinout == 'mandatory' ? 'in' : ($this->attribute ? $this->attribute->get("twofactor", "state") : ''); $available = count($this->tokenMods) + count($this->otpMods) > 0; // If the user is being redirected here because of mandatory two factor, then display a message saying so. if (!$available && $optinout == 'mandatory') { msg($this->getLang('mandatory'), -1); } elseif ($this->attribute->get("twofactor", "state") == '' && $optinout == 'optout') { msg($this->getLang('optout_notice'), 2); } elseif ($this->attribute->get("twofactor", "state") == 'in' && count($this->tokenMods) == 0 && count($this->otpMods) == 0) { msg($this->getLang('not_configured_notice'), 2); } global $USERINFO, $lang, $conf; $form = new Doku_Form(array('id' => 'twofactor_setup')); // Add the checkbox to opt in and out, only if optinout is not mandatory. $items = array(); if ($optinout != 'mandatory') { if (!$this->attribute || !$optinvalue) { // If there is no personal setting for optin, the default is based on the wiki default. $optinvalue = $this->getConf("optinout") == 'optout'; } $items[] = form_makeCheckboxField('optinout', '1', $this->getLang('twofactor_optin'), '', 'block', $optinvalue == 'in' ? array('checked' => 'checked') : array()); } // Add the notification checkbox if appropriate. if ($this->getConf('loginnotice') == 'user' && $optinvalue == 'in' && count($this->otpMods) > 0) { $loginnotice = $this->attribute ? $this->attribute->get("twofactor", "loginnotice") : false; $items[] = form_makeCheckboxField('loginnotice', '1', $this->getLang('twofactor_notify'), '', 'block', $loginnotice === true ? array('checked' => 'checked') : array()); } // Select a notification provider. if ($optinvalue == 'in') { // If there is more than one choice, have the user select the default. if (count($this->otpMods) > 1) { $defaultMod = $this->attribute->exists("twofactor", "defaultmod") ? $this->attribute->get("twofactor", "defaultmod") : null; $modList = array_merge(array($this->getLang('useallotp')), array_keys($this->otpMods)); $items[] = form_makeListboxField('default_module', $modList, $defaultMod, $this->getLang('defaultmodule'), '', 'block'); } } if (count($items) > 0) { $form->startFieldset($this->getLang('settings')); foreach ($items as $item) { $form->addElement($item); } $form->endFieldset(); } // TODO: Make this AJAX so that the user does not have to keep clicking // submit them Update Profile! // Loop through all modules and render the profile components. if ($optinvalue == 'in') { $parts = array(); foreach ($this->modules as $mod) { if ($mod->getConf("enable") == 1) { $this->log('twofactor_profile_form: processing ' . get_class($mod) . '::renderProfileForm()', self::LOGGING_DEBUG); $items = $mod->renderProfileForm(); if (count($items) > 0) { $form->startFieldset($mod->getLang('name')); foreach ($items as $item) { $form->addElement($item); } $form->endFieldset(); } } } } if ($conf['profileconfirm']) { $form->addElement('
'); $form->startFieldset($this->getLang('verify_password')); $form->addElement(form_makePasswordField('oldpass', $lang['oldpass'], '', 'block', array('size' => '50', 'required' => 'required'))); $form->endFieldset(); } $form->addElement('
'); $form->addElement(form_makeButton('submit', '', $lang['btn_save'])); $form->addElement('' . $this->getLang('btn_return') . ''); $form->addHidden('do', 'twofactor_profile'); $form->addHidden('save', '1'); echo '
' . NL . $form->getForm() . '
' . NL; */ } }