silverstripe /
silverstripe-totp-authenticator
| 1 | <?php |
||||
| 2 | |||||
| 3 | declare(strict_types=1); |
||||
| 4 | |||||
| 5 | namespace SilverStripe\TOTP; |
||||
| 6 | |||||
| 7 | use Exception; |
||||
| 8 | use Psr\Log\LoggerInterface; |
||||
| 9 | use RuntimeException; |
||||
| 10 | use SilverStripe\Control\HTTPRequest; |
||||
| 11 | use SilverStripe\Core\Injector\Injectable; |
||||
| 12 | use SilverStripe\Core\Injector\Injector; |
||||
| 13 | use SilverStripe\MFA\Exception\AuthenticationFailedException; |
||||
| 14 | use SilverStripe\MFA\Method\Handler\VerifyHandlerInterface; |
||||
| 15 | use SilverStripe\MFA\Model\RegisteredMethod; |
||||
| 16 | use SilverStripe\MFA\Service\EncryptionAdapterInterface; |
||||
| 17 | use SilverStripe\MFA\State\Result; |
||||
| 18 | use SilverStripe\MFA\Store\StoreInterface; |
||||
| 19 | |||||
| 20 | /** |
||||
| 21 | * Handles verification requests using a time-based one-time password (TOTP) with the silverstripe/mfa module. |
||||
| 22 | */ |
||||
| 23 | class VerifyHandler implements VerifyHandlerInterface |
||||
| 24 | { |
||||
| 25 | use Injectable; |
||||
| 26 | use TOTPAware; |
||||
| 27 | |||||
| 28 | /** |
||||
| 29 | * @var string[] |
||||
| 30 | */ |
||||
| 31 | private static $dependencies = [ |
||||
|
0 ignored issues
–
show
introduced
by
Loading history...
|
|||||
| 32 | 'Logger' => '%$' . LoggerInterface::class . '.mfa', |
||||
| 33 | ]; |
||||
| 34 | |||||
| 35 | /** |
||||
| 36 | * @var LoggerInterface |
||||
| 37 | */ |
||||
| 38 | protected $logger; |
||||
| 39 | |||||
| 40 | public function start(StoreInterface $store, RegisteredMethod $method): array |
||||
| 41 | { |
||||
| 42 | try { |
||||
| 43 | $data = json_decode((string) $method->Data, true); |
||||
| 44 | if (!$data || !isset($data['secret'])) { |
||||
| 45 | throw new RuntimeException('TOTP secret is not available in the registered method data'); |
||||
| 46 | } |
||||
| 47 | |||||
| 48 | $key = $this->getEncryptionKey(); |
||||
| 49 | if (empty($key)) { |
||||
| 50 | throw new AuthenticationFailedException( |
||||
| 51 | 'Please define a SS_MFA_SECRET_KEY environment variable for encryption' |
||||
| 52 | ); |
||||
| 53 | } |
||||
| 54 | |||||
| 55 | // Decrypt the TOTP secret from the registered method |
||||
| 56 | $secret = Injector::inst()->get(EncryptionAdapterInterface::class)->decrypt($data['secret'], $key); |
||||
| 57 | |||||
| 58 | $store->setState([ |
||||
| 59 | 'secret' => $secret, |
||||
| 60 | ]); |
||||
| 61 | |||||
| 62 | $enabled = true; |
||||
| 63 | } catch (Exception $ex) { |
||||
| 64 | // noop: encryption may not be defined, so method should be disabled rather than application error |
||||
| 65 | $enabled = false; |
||||
| 66 | |||||
| 67 | $this->getLogger()->debug($ex->getMessage(), $ex->getTrace()); |
||||
| 68 | } |
||||
| 69 | |||||
| 70 | return [ |
||||
| 71 | 'enabled' => $enabled, |
||||
| 72 | 'codeLength' => $method->getMethod()->getCodeLength(), |
||||
|
0 ignored issues
–
show
The method
getCodeLength() does not exist on SilverStripe\MFA\Method\MethodInterface. It seems like you code against a sub-type of SilverStripe\MFA\Method\MethodInterface such as SilverStripe\TOTP\Method.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 73 | ]; |
||||
| 74 | } |
||||
| 75 | |||||
| 76 | public function verify(HTTPRequest $request, StoreInterface $store, RegisteredMethod $registeredMethod): Result |
||||
| 77 | { |
||||
| 78 | $data = json_decode($request->getBody(), true); |
||||
| 79 | if (!$this->getTotp($store)->verify($data['code'] ?? '')) { |
||||
| 80 | return Result::create(false, _t(__CLASS__ . '.INVALID_CODE', 'Invalid code')); |
||||
| 81 | } |
||||
| 82 | return Result::create(); |
||||
| 83 | } |
||||
| 84 | |||||
| 85 | public function getComponent(): string |
||||
| 86 | { |
||||
| 87 | return 'TOTPVerify'; |
||||
| 88 | } |
||||
| 89 | |||||
| 90 | /** |
||||
| 91 | * @return LoggerInterface |
||||
| 92 | */ |
||||
| 93 | public function getLogger(): ?LoggerInterface |
||||
| 94 | { |
||||
| 95 | return $this->logger; |
||||
| 96 | } |
||||
| 97 | |||||
| 98 | /** |
||||
| 99 | * @param LoggerInterface $logger |
||||
| 100 | * @return VerifyHandler |
||||
| 101 | */ |
||||
| 102 | public function setLogger(LoggerInterface $logger): VerifyHandler |
||||
| 103 | { |
||||
| 104 | $this->logger = $logger; |
||||
| 105 | return $this; |
||||
| 106 | } |
||||
| 107 | } |
||||
| 108 |