This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * Multi-factor authentication for Yii2 projects |
||
4 | * |
||
5 | * @link https://github.com/hiqdev/yii2-mfa |
||
6 | * @package yii2-mfa |
||
7 | * @license BSD-3-Clause |
||
8 | * @copyright Copyright (c) 2016-2018, HiQDev (http://hiqdev.com/) |
||
9 | */ |
||
10 | |||
11 | namespace hiqdev\yii2\mfa\controllers; |
||
12 | |||
13 | use hiqdev\yii2\mfa\base\ApiMfaIdentityInterface; |
||
14 | use hiqdev\yii2\mfa\base\MfaIdentityInterface; |
||
15 | use hiqdev\yii2\mfa\behaviors\OauthLoginBehavior; |
||
16 | use hiqdev\yii2\mfa\forms\InputForm; |
||
17 | use hiqdev\yii2\mfa\validator\BackUrlValidatorInterface; |
||
18 | use Yii; |
||
19 | use yii\filters\AccessControl; |
||
20 | use yii\filters\ContentNegotiator; |
||
21 | use yii\filters\VerbFilter; |
||
22 | use yii\web\Response; |
||
23 | |||
24 | /** |
||
25 | * TOTP controller. |
||
26 | * Time-based One Time Password. |
||
27 | */ |
||
28 | class TotpController extends \yii\web\Controller |
||
29 | { |
||
30 | private const TOTP_BACK_URL = 'totp-back-url'; |
||
31 | |||
32 | public $enableCsrfValidation = false; |
||
33 | |||
34 | public function behaviors() |
||
35 | { |
||
36 | return array_merge(parent::behaviors(), [ |
||
37 | 'filterApi' => [ |
||
38 | 'class' => OauthLoginBehavior::class, |
||
39 | 'only' => ['api-temporary-secret', 'api-disable', 'api-enable'], |
||
40 | ], |
||
41 | 'access' => [ |
||
42 | 'class' => AccessControl::class, |
||
43 | 'denyCallback' => [$this, 'denyCallback'], |
||
44 | 'rules' => [ |
||
45 | // ? - guest |
||
46 | [ |
||
47 | 'actions' => ['check'], |
||
48 | 'roles' => ['?'], |
||
49 | 'allow' => true, |
||
50 | ], |
||
51 | // @ - authenticated |
||
52 | [ |
||
53 | 'actions' => ['enable', 'disable', 'toggle', 'api-temporary-secret', 'api-disable', 'api-enable', 'back'], |
||
54 | 'roles' => ['@'], |
||
55 | 'allow' => true, |
||
56 | ], |
||
57 | ], |
||
58 | ], |
||
59 | 'verbFilter' => [ |
||
60 | 'class' => VerbFilter::class, |
||
61 | 'actions' => [ |
||
62 | 'api-temporary-secret' => ['POST'], |
||
63 | 'api-enable' => ['POST'], |
||
64 | 'api-disable' => ['POST'], |
||
65 | ], |
||
66 | ], |
||
67 | 'contentNegotiator' => [ |
||
68 | 'class' => ContentNegotiator::class, |
||
69 | 'only' => ['api-temporary-secret', 'api-disable', 'api-enable'], |
||
70 | 'formats' => [ |
||
71 | 'application/json' => Response::FORMAT_JSON, |
||
72 | ], |
||
73 | ], |
||
74 | ]); |
||
75 | } |
||
76 | |||
77 | public function denyCallback() |
||
78 | { |
||
79 | return $this->goHome(); |
||
80 | } |
||
81 | |||
82 | public function actionEnable($back = null) |
||
83 | { |
||
84 | /** @var MfaIdentityInterface $user */ |
||
85 | $user = Yii::$app->user->identity; |
||
86 | if ($user->getTotpSecret()) { |
||
87 | Yii::$app->session->setFlash('error', Yii::t('mfa', 'Two-factor authentication is already enabled. Disable first.')); |
||
88 | |||
89 | return empty($back) ? $this->goHome() : $this->deferredRedirect($back); |
||
90 | } |
||
91 | |||
92 | $model = new InputForm(); |
||
93 | $secret = $this->module->getTotp()->getSecret(); |
||
94 | |||
95 | if ($model->load(Yii::$app->request->post()) && $model->validate()) { |
||
96 | if ($this->module->getTotp()->verifyCode($secret, $model->code)) { |
||
97 | $user->setTotpSecret($secret); |
||
98 | $this->module->getTotp()->setIsVerified(true); |
||
99 | if ($user->save() && Yii::$app->user->login($user)) { |
||
100 | Yii::$app->session->setFlash('success', Yii::t('mfa', 'Two-factor authentication successfully enabled.')); |
||
101 | |||
102 | return empty($back) ? $this->goBack() : $this->deferredRedirect($back); |
||
103 | } else { |
||
104 | Yii::$app->session->setFlash('error', Yii::t('mfa', 'Sorry, we have failed to enable two-factor authentication.')); |
||
105 | |||
106 | return empty($back) ? $this->goHome() : $this->deferredRedirect($back); |
||
107 | } |
||
108 | } else { |
||
109 | $model->addError('code', Yii::t('mfa', 'Wrong verification code. Please verify your secret and try again.')); |
||
110 | } |
||
111 | } |
||
112 | |||
113 | $qrcode = $this->module->getTotp()->getQRCodeImageAsDataUri($user->getUsername(), $secret); |
||
114 | |||
115 | return $this->render('enable', compact('model', 'secret', 'qrcode')); |
||
116 | } |
||
117 | |||
118 | public function actionDisable($back = null) |
||
119 | { |
||
120 | /** @var MfaIdentityInterface $user */ |
||
121 | $user = Yii::$app->user->identity; |
||
122 | $model = new InputForm(); |
||
123 | $secret = $user->getTotpSecret(); |
||
124 | |||
125 | if ($model->load(Yii::$app->request->post()) && $model->validate()) { |
||
126 | if ($this->module->getTotp()->verifyCode($secret, $model->code)) { |
||
127 | $this->module->getTotp()->removeSecret(); |
||
128 | $user->setTotpSecret(''); |
||
129 | if ($user->save()) { |
||
130 | Yii::$app->session->setFlash('success', Yii::t('mfa', 'Two-factor authentication successfully disabled.')); |
||
131 | } |
||
132 | |||
133 | return empty($back) ? $this->goBack() : $this->deferredRedirect($back); |
||
134 | } else { |
||
135 | $model->addError('code', Yii::t('mfa', 'Wrong verification code. Please verify your secret and try again.')); |
||
136 | } |
||
137 | } |
||
138 | return $this->render('disable', compact('model')); |
||
139 | } |
||
140 | |||
141 | public function actionBack() |
||
142 | { |
||
143 | $url = Yii::$app->getSession()->get(self::TOTP_BACK_URL); |
||
144 | if (empty($url)) { |
||
145 | return $this->goBack(); |
||
146 | } |
||
147 | Yii::$app->getSession()->remove(self::TOTP_BACK_URL); |
||
148 | |||
149 | return $this->redirect($url); |
||
150 | } |
||
151 | |||
152 | public function deferredRedirect($url = null) |
||
153 | { |
||
154 | if (!empty($url) && Yii::createObject(BackUrlValidatorInterface::class)->validate($url)) { |
||
155 | Yii::$app->getSession()->set(self::TOTP_BACK_URL, $url); |
||
156 | } |
||
157 | return $this->render('redirect'); |
||
158 | } |
||
159 | |||
160 | public function actionToggle($back = null) |
||
161 | { |
||
162 | /** @var MfaIdentityInterface $user */ |
||
163 | $user = Yii::$app->user->identity; |
||
164 | |||
165 | return empty($user->getTotpSecret()) ? $this->actionEnable($back) : $this->actionDisable($back); |
||
166 | } |
||
167 | |||
168 | public function actionCheck() |
||
169 | { |
||
170 | /** @var MfaIdentityInterface $user */ |
||
171 | $user = $this->module->getHalfUser(); |
||
172 | $model = new InputForm(); |
||
173 | $secret = $user->getTotpSecret(); |
||
174 | |||
175 | if ($model->load(Yii::$app->request->post()) && $model->validate()) { |
||
176 | if ($this->module->getTotp()->verifyCode($secret, $model->code)) { |
||
177 | $this->module->getTotp()->setIsVerified(true); |
||
178 | Yii::$app->user->login($user); |
||
179 | |||
180 | return $this->goBack(); |
||
181 | } else { |
||
182 | $model->addError('code', Yii::t('mfa', 'Wrong verification code. Please verify your secret and try again.')); |
||
183 | } |
||
184 | } |
||
185 | |||
186 | return $this->render('check', [ |
||
187 | 'model' => $model, |
||
188 | 'issuer' => $this->module->getTotp()->issuer, |
||
189 | 'username' => $user->getUsername(), |
||
190 | ]); |
||
191 | } |
||
192 | |||
193 | /** |
||
194 | * @inheritDoc |
||
195 | */ |
||
196 | public function goBack($defaultUrl = null) |
||
197 | { |
||
198 | $redirectUrl = Yii::$app->params['totpRedirectBackAction.url']; |
||
199 | if (!empty($redirectUrl)) { |
||
200 | return $this->redirect($redirectUrl); |
||
201 | } |
||
202 | |||
203 | return parent::goBack($defaultUrl); |
||
204 | } |
||
205 | |||
206 | public function actionApiEnable() |
||
207 | { |
||
208 | /** @var ApiMfaIdentityInterface $identity */ |
||
209 | $identity = \Yii::$app->user->identity; |
||
210 | $secret = $identity->getTotpSecret(); |
||
211 | if (!empty($secret)) { |
||
212 | return ['_error' => 'mfa already enabled' . $secret]; |
||
213 | } |
||
214 | |||
215 | if (!$this->module->getTotp()->verifyCode($identity->getTemporarySecret(), $this->request->post('code', ''))) { |
||
216 | return ['_error' => 'invalid totp code']; |
||
217 | } |
||
218 | |||
219 | $identity->setTotpSecret($identity->getTemporarySecret()); |
||
220 | $identity->setTemporarySecret(null); |
||
221 | $identity->save(); |
||
222 | |||
223 | return ['id' => $identity->getId()]; |
||
0 ignored issues
–
show
|
|||
224 | } |
||
225 | |||
226 | public function actionApiDisable() |
||
227 | { |
||
228 | /** @var ApiMfaIdentityInterface $identity */ |
||
229 | $identity = \Yii::$app->user->identity; |
||
230 | $secret = $identity->getTotpSecret(); |
||
231 | if (empty($secret)) { |
||
232 | return ['_error' => 'mfa disabled, enable first']; |
||
233 | } |
||
234 | |||
235 | if (!$this->module->getTotp()->verifyCode($secret, $this->request->post('code', ''))) { |
||
236 | return ['_error' => 'invalid totp code']; |
||
237 | } |
||
238 | |||
239 | $identity->setTotpSecret(''); |
||
240 | $identity->save(); |
||
241 | |||
242 | return ['id' => $identity->getId()]; |
||
0 ignored issues
–
show
The method
getId() does not seem to exist on object<hiqdev\yii2\mfa\b...piMfaIdentityInterface> .
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed.
Loading history...
|
|||
243 | } |
||
244 | |||
245 | public function actionApiTemporarySecret() |
||
246 | { |
||
247 | /** @var ApiMfaIdentityInterface $identity */ |
||
248 | $identity = \Yii::$app->user->identity; |
||
249 | $secret = $this->module->getTotp()->getSecret(); |
||
250 | $identity->setTemporarySecret($secret); |
||
251 | $identity->save(); |
||
252 | |||
253 | return ['secret' => $secret]; |
||
254 | } |
||
255 | } |
||
256 |
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.
This is most likely a typographical error or the method has been renamed.