Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
chihiro-adachi committed Jan 12, 2023
0 parents commit 3e25c03
Show file tree
Hide file tree
Showing 12 changed files with 1,379 additions and 0 deletions.
179 changes: 179 additions & 0 deletions Controller/TwoFactorAuthCustomerSmsController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
<?php

namespace Plugin\TwoFactorAuthCustomerSms42\Controller;

use Plugin\TwoFactorAuthCustomer42\Controller\TwoFactorAuthCustomerController;
use Plugin\TwoFactorAuthCustomer42\Form\Type\TwoFactorAuthSmsTypeCustomer;
use Plugin\TwoFactorAuthCustomer42\Form\Type\TwoFactorAuthPhoneNumberTypeCustomer;
use Plugin\TwoFactorAuthCustomer42\Service\CustomerTwoFactorAuthService;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;


class TwoFactorAuthCustomerSmsController extends TwoFactorAuthCustomerController
{

/**
* SMS認証 送信先入力画面.
* @Route("/two_factor_auth/tfa/sms/send_onetime", name="plg_customer_2fa_sms_send_onetime", methods={"GET", "POST"})

This comment has been minimized.

Copy link
@kiy0taka

kiy0taka Feb 3, 2023

Contributor

ログイン必須のルートは /mypage/ 以下に。

* @Template("TwoFactorAuthCustomerSms42/Resource/template/default/tfa/sms/send.twig")
*/
public function inputPhoneNumber(Request $request)
{
if ($this->isAuth()) {
return $this->redirectToRoute($this->getCallbackRoute());
}

$error = null;
/** @var Customer $Customer */
$Customer = $this->getUser();
$builder = $this->formFactory->createBuilder(TwoFactorAuthPhoneNumberTypeCustomer::class);
$form = null;
// 入力フォーム生成
$form = $builder->getForm();

// デバイス認証済み電話番号が設定済みの場合は優先して利用
$phoneNumber = ($Customer->getDeviceAuthedPhoneNumber() != null ? $Customer->getDeviceAuthedPhoneNumber() : $Customer->getTwoFactorAuthedPhoneNumber());

This comment has been minimized.

Copy link
@kiy0taka

kiy0taka Feb 3, 2023

Contributor

優先するのは TwoFactorAuthedPhoneNumber の方ではないでしょうか?


if ('POST' === $request->getMethod()) {
$form->handleRequest($request);
if ($form->isSubmitted()) {
if ($Customer->isTwoFactorAuth() && $phoneNumber) {
// 初回認証済み
// 前回送信した電話番号へワンタイムコードを送信
$this->sendToken($Customer, $phoneNumber);
$response = new RedirectResponse($this->generateUrl('plg_customer_2fa_sms_input_onetime'));
// 送信電話番号をセッションへ一時格納
$this->session->set(
CustomerTwoFactorAuthService::SESSION_AUTHED_PHONE_NUMBER,
$phoneNumber
);
return $response;
} else {
// 初回認証時
if ($form->isValid()) {
$phoneNumber = $form->get('phone_number')->getData();
// 入力された電話番号へワンタイムコードを送信
$this->sendToken($Customer, $phoneNumber);
$response = new RedirectResponse($this->generateUrl('plg_customer_2fa_sms_input_onetime'));
// 送信電話番号をセッションへ一時格納
$this->session->set(
CustomerTwoFactorAuthService::SESSION_AUTHED_PHONE_NUMBER,
$phoneNumber
);
return $response;
} else {
$error = trans('front.2fa.sms.send.failure_message');
}
}
}
}

return [
'form' => $form->createView(),
'Customer' => $Customer,
'phoneNumber' => $phoneNumber,
'error' => $error,
];
}

/**
* SMS認証 ワンタイムトークン入力画面.
* @Route("/two_factor_auth/tfa/sms/input_onetime", name="plg_customer_2fa_sms_input_onetime", methods={"GET", "POST"})

This comment has been minimized.

Copy link
@kiy0taka

kiy0taka Feb 3, 2023

Contributor

ログイン必須のルートは /mypage/ 以下に。

* @Template("TwoFactorAuthCustomerSms42/Resource/template/default/tfa/sms/input.twig")
*/
public function inputToken(Request $request)
{
if ($this->isAuth()) {
return $this->redirectToRoute($this->getCallbackRoute());
}

$error = null;
/** @var Customer $Customer */
$Customer = $this->getUser();
$builder = $this->formFactory->createBuilder(TwoFactorAuthSmsTypeCustomer::class);
$form = null;
$auth_key = null;
// 入力フォーム生成
$form = $builder->getForm();
if ('POST' === $request->getMethod()) {
$form->handleRequest($request);
$token = $form->get('one_time_token')->getData();
if ($form->isSubmitted() && $form->isValid()) {
if (!$this->checkToken($Customer, $token)) {
// ワンタイムトークン不一致 or 有効期限切れ
$error = trans('front.2fa.onetime.invalid_message__reinput');
} else {
// 送信電話番号をセッションより取得
$phoneNumber = $this->session->get(CustomerTwoFactorAuthService::SESSION_AUTHED_PHONE_NUMBER);
// ワンタイムトークン一致
// 二段階認証完了
$Customer->setTwoFactorAuth(true);
$Customer->setTwoFactorAuthedPhoneNumber($phoneNumber);
$this->entityManager->persist($Customer);
$this->entityManager->flush();

$response = new RedirectResponse($this->generateUrl($this->getCallbackRoute()));
$response->headers->setCookie(
$this->customerTwoFactorAuthService->createAuthedCookie(
$Customer,
$this->getCallbackRoute()
)
);
return $response;
}
} else {
$error = trans('front.2fa.onetime.invalid_message__reinput');
}
}

return [
'form' => $form->createView(),
'Customer' => $Customer,
'error' => $error,
];
}

/**
* ワンタイムトークンを送信.
*
* @param \Eccube\Entity\Customer $Customer
* @param string $phoneNumber
*
*/
private function sendToken($Customer, $phoneNumber)
{
// ワンタイムトークン生成・保存
$token = $Customer->createTwoFactorAuthOneTimeToken();
$this->entityManager->persist($Customer);
$this->entityManager->flush();

// ワンタイムトークン送信メッセージをレンダリング
$twig = 'TwoFactorAuthCustomer42/Resource/template/default/sms/onetime_message.twig';
$body = $this->twig->render($twig , [
'Customer' => $Customer,
'token' => $token,
]);

// SMS送信
return $this->customerTwoFactorAuthService->sendBySms($Customer, $phoneNumber, $body);
}

/**
* ワンタイムトークンチェック.
*
* @return boolean
*/
private function checkToken($Customer, $token)
{
$now = new \DateTime();
if ($Customer->getTwoFactorAuthOneTimeToken() !== $token
|| $Customer->getTwoFactorAuthOneTimeTokenExpire() < $now) {
return false;
}
return true;
}

}
109 changes: 109 additions & 0 deletions Entity/CustomerTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<?php

namespace Plugin\TwoFactorAuthCustomerSms42\Entity;

use Doctrine\ORM\Mapping as ORM;
use Eccube\Annotation\EntityExtension;

/**
* @EntityExtension("Eccube\Entity\Customer")
*/
trait CustomerTrait
{
/**
* @var string|null
*
* @ORM\Column(name="two_factor_authed_phone_number", type="string", length=14, nullable=true)
*/
private $two_factor_authed_phone_number;

/**
* @var ?string
*
* @ORM\Column(name="two_factor_auth_one_time_token", type="string", length=10, nullable=true)
*/
private ?string $two_factor_auth_one_time_token;

/**
* @var \DateTime|null
*
* @ORM\Column(name="two_factor_auth_one_time_token_expire", type="datetimetz", nullable=true)
*/
private $two_factor_auth_one_time_token_expire;


/**
* @return string
*/
public function getTwoFactorAuthedPhoneNumber(): ?string
{
return $this->two_factor_authed_phone_number;
}

/**
* @param string $two_factor_authed_phone_number
*/
public function setTwoFactorAuthedPhoneNumber(string $two_factor_authed_phone_number): void
{
$this->two_factor_authed_phone_number = $two_factor_authed_phone_number;
}

/**
* @return string
*/
public function createTwoFactorAuthOneTimeToken(): ?string
{
$now = new \DateTime();

// TODO: なんちゃって
$token = '';
for ($i = 0; $i < 6; $i++) {
$token .= (string)rand(0, 9);
}

$this->setTwoFactorAuthOneTimeToken($token);
$this->setTwoFactorAuthOneTimeTokenExpire($now->modify('+5 mins'));
return $token;
}

/**
* @return string
*/
public function getTwoFactorAuthOneTimeToken(): ?string
{
return $this->two_factor_auth_one_time_token;
}

/**
* @param string $two_factor_auth_one_time_token
*/
public function setTwoFactorAuthOneTimeToken(?string $two_factor_auth_one_time_token): void
{
$this->two_factor_auth_one_time_token = $two_factor_auth_one_time_token;
}

/**
* Set oneTimeTokenExpire.
*
* @param \DateTime|null $resetExpire
*
* @return Customer
*/
public function setTwoFactorAuthOneTimeTokenExpire($deviceAuthOneTimeTokenExpire = null)
{
$this->two_factor_auth_one_time_token_expire = $deviceAuthOneTimeTokenExpire;

return $this;
}

/**
* Get resetExpire.
*
* @return \DateTime|null
*/
public function getTwoFactorAuthOneTimeTokenExpire()
{
return $this->two_factor_auth_one_time_token_expire;
}

}
108 changes: 108 additions & 0 deletions Event.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
<?php

/*
* This file is part of EC-CUBE
*
* Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved.
*
* http://www.ec-cube.co.jp/
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Plugin\TwoFactorAuthCustomerSms42;

use Eccube\Entity\BaseInfo;
use Eccube\Repository\BaseInfoRepository;
use Doctrine\ORM\EntityManagerInterface;
use Eccube\Event\EccubeEvents;
use Eccube\Event\EventArgs;
use Eccube\Event\TemplateEvent;
use Eccube\Request\Context;
use Plugin\TwoFactorAuthCustomer42\Repository\BaseTwoFactorAuthSettingRepository;
use Plugin\TwoFactorAuthCustomer42\Service\CustomerTwoFactorAuthService;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Filesystem\Filesystem;

/**
* Class Event.
*/
class Event implements EventSubscriberInterface
{
/**
* @var ContainerInterface
*/
protected $container;

/**
* @var BaseInfo
*/
protected $BaseInfo;

/**
* @var CustomerTwoFactorAuthService
*/
protected $customerTwoFactorAuthService;

/**
* @var EntityManagerInterface
*/
private $entityManager;

/**
* @var \Twig_Environment
*/
private $twig;

/**
* @var NotifierInterface
*/
//private $notifier;

/**
* Event constructor.
*
* @param ContainerInterface $container
* @param BaseInfoRepository $baseInfoRepository
* @param EntityManagerInterface $entityManager
* @param CustomerTwoFactorAuthService $customerTwoFactorAuthService
* @param \Twig_Environment $twig
*/
public function __construct(
ContainerInterface $container,
BaseInfoRepository $baseInfoRepository,
EntityManagerInterface $entityManager,
CustomerTwoFactorAuthService $customerTwoFactorAuthService,
\Twig_Environment $twig
)
{
$this->container = $container;
$this->BaseInfo = $baseInfoRepository->get();
$this->entityManager = $entityManager;
$this->customerTwoFactorAuthService = $customerTwoFactorAuthService;
$this->twig = $twig;
}

public static function getSubscribedEvents(): array
{
return [
'@admin/Customer/edit.twig' => 'onRenderAdminCustomerEdit',
];
}

/**
* [/admin/customer/edit]表示の時のEvent Fork.
* 二段階認証関連項目を追加する.
*
* @param TemplateEvent $event
*/
public function onRenderAdminCustomerEdit(TemplateEvent $event)
{
// add twig
$twig = 'TwoFactorAuthCustomerSms42/Resource/template/admin/customer_edit.twig';
$event->addSnippet($twig);
}

}
Loading

0 comments on commit 3e25c03

Please sign in to comment.