Add explanatory texts to reauthentication
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / form / MultifactorAuthenticationForm.class.php
1 <?php
2 namespace wcf\form;
3 use wcf\data\object\type\ObjectType;
4 use wcf\data\user\User;
5 use wcf\form\AbstractFormBuilderForm;
6 use wcf\system\application\ApplicationHandler;
7 use wcf\system\cache\runtime\UserProfileRuntimeCache;
8 use wcf\system\exception\IllegalLinkException;
9 use wcf\system\exception\NamedUserException;
10 use wcf\system\form\builder\TemplateFormNode;
11 use wcf\system\request\LinkHandler;
12 use wcf\system\user\multifactor\IMultifactorMethod;
13 use wcf\system\user\multifactor\Setup;
14 use wcf\system\WCF;
15 use wcf\util\HeaderUtil;
16
17 /**
18 * Represents the multi-factor authentication form.
19 *
20 * @author Tim Duesterhus
21 * @copyright 2001-2020 WoltLab GmbH
22 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
23 * @package WoltLabSuite\Core\Form
24 * @since 5.4
25 */
26 class MultifactorAuthenticationForm extends AbstractFormBuilderForm {
27 const AVAILABLE_DURING_OFFLINE_MODE = true;
28
29 /**
30 * @inheritDoc
31 */
32 public $formAction = 'authenticate';
33
34 /**
35 * @var User
36 */
37 private $user;
38
39 /**
40 * @var Setup[]
41 */
42 private $setups;
43
44 /**
45 * @var ObjectType
46 */
47 private $method;
48
49 /**
50 * @var IMultifactorMethod
51 */
52 private $processor;
53
54 /**
55 * @var Setup
56 */
57 private $setup;
58
59 /**
60 * @var string
61 */
62 public $redirectUrl;
63
64 /**
65 * @inheritDoc
66 */
67 public function readParameters() {
68 parent::readParameters();
69
70 if (!empty($_GET['url']) && ApplicationHandler::getInstance()->isInternalURL($_GET['url'])) {
71 $this->redirectUrl = $_GET['url'];
72 }
73
74 if (WCF::getUser()->userID) {
75 $this->performRedirect();
76 }
77
78 $this->user = WCF::getSession()->getPendingUserChange();
79 if (!$this->user) {
80 throw new NamedUserException(WCF::getLanguage()->getDynamicVariable(
81 'wcf.user.security.multifactor.authentication.noPendingUserChange'
82 ));
83 }
84
85 $this->setups = Setup::getAllForUser($this->user);
86
87 if (empty($this->setups)) {
88 throw new NamedUserException(WCF::getLanguage()->getDynamicVariable(
89 'wcf.user.security.multifactor.authentication.noSetup',
90 [
91 'user' => $this->user,
92 ]
93 ));
94 }
95
96 \uasort($this->setups, function (Setup $a, Setup $b) {
97 return $b->getObjectType()->priority <=> $a->getObjectType()->priority;
98 });
99
100 $setupId = \array_keys($this->setups)[0];
101 if (isset($_GET['id'])) {
102 $setupId = intval($_GET['id']);
103 }
104
105 if (!isset($this->setups[$setupId])) {
106 throw new IllegalLinkException();
107 }
108
109 $this->setup = $this->setups[$setupId];
110 $this->method = $this->setup->getObjectType();
111 \assert($this->method->getDefinition()->definitionName === 'com.woltlab.wcf.multifactor');
112
113 $this->processor = $this->method->getProcessor();
114 }
115
116 /**
117 * @inheritDoc
118 */
119 protected function createForm() {
120 parent::createForm();
121
122 $this->form->appendChild(
123 TemplateFormNode::create('loginAs')
124 ->templateName('__multifactorAuthenticationLoginAs')
125 );
126
127 $this->processor->createAuthenticationForm($this->form, $this->setup);
128 }
129
130 public function save() {
131 AbstractForm::save();
132
133 WCF::getDB()->beginTransaction();
134
135 $setup = $this->setup->lock();
136
137 $this->processor->processAuthenticationForm($this->form, $setup);
138
139 WCF::getDB()->commitTransaction();
140
141 WCF::getSession()->applyPendingUserChange($this->user);
142
143 $this->saved();
144 }
145
146 /**
147 * @inheritDoc
148 */
149 public function saved() {
150 AbstractForm::saved();
151
152 $this->performRedirect();
153 }
154
155 /**
156 * Returns to the redirectUrl if given and to the landing page otherwise.
157 */
158 protected function performRedirect() {
159 if ($this->redirectUrl) {
160 HeaderUtil::redirect($this->redirectUrl);
161 }
162 else {
163 HeaderUtil::redirect(LinkHandler::getInstance()->getLink());
164 }
165 exit;
166 }
167
168 /**
169 * @inheritDoc
170 */
171 protected function setFormAction() {
172 $this->form->action(LinkHandler::getInstance()->getControllerLink(static::class, [
173 'object' => $this->setup,
174 'url' => $this->redirectUrl,
175 ]));
176 }
177
178 /**
179 * @inheritDoc
180 */
181 public function assignVariables() {
182 parent::assignVariables();
183
184 WCF::getTPL()->assign([
185 'setups' => $this->setups,
186 'user' => $this->user,
187 'userProfile' => UserProfileRuntimeCache::getInstance()->getObject($this->user->userID),
188 'setup' => $this->setup,
189 'redirectUrl' => $this->redirectUrl,
190 ]);
191 }
192 }