Skip to content

Commit

Permalink
パスワードのマイグレーションに対応
Browse files Browse the repository at this point in the history
  • Loading branch information
chihiro-adachi committed Jan 30, 2024
1 parent c1a5568 commit 3e1d7b7
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 8 deletions.
5 changes: 3 additions & 2 deletions src/Eccube/Entity/Customer.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\LegacyPasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Validator\Constraints as Assert;
Expand All @@ -30,7 +31,7 @@
* @ORM\HasLifecycleCallbacks()
* @ORM\Entity(repositoryClass="Eccube\Repository\CustomerRepository")
*/
class Customer extends \Eccube\Entity\AbstractEntity implements UserInterface, PasswordAuthenticatedUserInterface, \Serializable
class Customer extends \Eccube\Entity\AbstractEntity implements UserInterface, PasswordAuthenticatedUserInterface, LegacyPasswordAuthenticatedUserInterface, \Serializable
{
/**
* @var int
Expand Down Expand Up @@ -680,7 +681,7 @@ public function setSalt($salt = null)
*
* @return string|null
*/
public function getSalt()
public function getSalt(): ?string
{
return $this->salt;
}
Expand Down
5 changes: 3 additions & 2 deletions src/Eccube/Entity/Member.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\LegacyPasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Validator\Constraints as Assert;
Expand All @@ -30,7 +31,7 @@
* @ORM\HasLifecycleCallbacks()
* @ORM\Entity(repositoryClass="Eccube\Repository\MemberRepository")
*/
class Member extends \Eccube\Entity\AbstractEntity implements UserInterface, PasswordAuthenticatedUserInterface, \Serializable
class Member extends \Eccube\Entity\AbstractEntity implements UserInterface, PasswordAuthenticatedUserInterface, LegacyPasswordAuthenticatedUserInterface, \Serializable
{
public static function loadValidatorMetadata(ClassMetadata $metadata)
{
Expand Down Expand Up @@ -338,7 +339,7 @@ public function setSalt($salt)
*
* @return string
*/
public function getSalt()
public function getSalt(): ?string
{
return $this->salt;
}
Expand Down
19 changes: 17 additions & 2 deletions src/Eccube/Security/Core/User/CustomerProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,33 @@

namespace Eccube\Security\Core\User;

use Doctrine\ORM\EntityManagerInterface;
use Eccube\Entity\Customer;
use Eccube\Entity\Master\CustomerStatus;
use Eccube\Repository\CustomerRepository;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\Exception\UserNotFoundException;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\PasswordUpgraderInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;

class CustomerProvider implements UserProviderInterface
class CustomerProvider implements UserProviderInterface, PasswordUpgraderInterface
{
/**
* @var CustomerRepository
*/
protected $customerRepository;

public function __construct(CustomerRepository $customerRepository)
/**
* @var EntityManagerInterface
*/
private $entityManager;

public function __construct(CustomerRepository $customerRepository, EntityManagerInterface $entityManager)
{
$this->customerRepository = $customerRepository;
$this->entityManager = $entityManager;
}

/**
Expand Down Expand Up @@ -92,4 +101,10 @@ public function loadUserByIdentifier(string $identifier): UserInterface
// FIXME deprecated
return $this->loadUserByUsername($identifier);
}

public function upgradePassword(PasswordAuthenticatedUserInterface $user, string $newHashedPassword): void
{
$user->setPassword($newHashedPassword);
$this->entityManager->flush();
}
}
19 changes: 17 additions & 2 deletions src/Eccube/Security/Core/User/MemberProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,33 @@

namespace Eccube\Security\Core\User;

use Doctrine\ORM\EntityManagerInterface;
use Eccube\Entity\Master\Work;
use Eccube\Entity\Member;
use Eccube\Repository\MemberRepository;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\Exception\UserNotFoundException;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\PasswordUpgraderInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;

class MemberProvider implements UserProviderInterface
class MemberProvider implements UserProviderInterface, PasswordUpgraderInterface
{
/**
* @var MemberRepository
*/
protected $memberRepository;

public function __construct(MemberRepository $memberRepository)
/**
* @var EntityManagerInterface
*/
private $entityManager;

public function __construct(MemberRepository $memberRepository, EntityManagerInterface $entityManager)
{
$this->memberRepository = $memberRepository;
$this->entityManager = $entityManager;
}

/**
Expand Down Expand Up @@ -89,4 +98,10 @@ public function loadUserByIdentifier(string $identifier): UserInterface
// FIXME deprecated
return $this->loadUserByUsername($identifier);
}

public function upgradePassword(PasswordAuthenticatedUserInterface $user, string $newHashedPassword): void
{
$user->setPassword($newHashedPassword);
$this->entityManager->flush();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<?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 Eccube\Tests\Security\PasswordHasher;

use Eccube\Entity\Member;
use Eccube\Security\PasswordHasher\PasswordHasher;
use Eccube\Tests\EccubeTestCase;
use Eccube\Util\StringUtil;
use Symfony\Component\PasswordHasher\LegacyPasswordHasherInterface;

class PasswordMigrationTest extends EccubeTestCase
{
/**
* @var LegacyPasswordHasherInterface
*/
private $legacyPasswordHasher;

public function setUp(): void
{
parent::setUp();
$this->legacyPasswordHasher = self::getContainer()->get(PasswordHasher::class);
}

/**
* EC-CUBEのハッシュアルゴリズムからSymfony標準のハッシュアルゴリズムへマイグレーションできることを確認する
*/
public function testPasswordMigration()
{
// 旧アルゴリズムでパスワードをハッシュ化
$username = 'migration-test-uesr';
$password = 'password';
$salt = StringUtil::random();
$hash = $this->legacyPasswordHasher->hash($password, $salt);

$Member = $this->createMember();
$Member->setLoginId($username)
->setPassword($hash)
->setSalt($salt);
$this->entityManager->flush();

// ログイン
$crawler = $this->client->request('GET', '/admin/login');
self::assertTrue($this->client->getResponse()->isSuccessful());

$form = $crawler->selectButton('ログイン')->form();
$form['login_id'] = $username;
$form['password'] = $password;
$this->client->submit($form);

self::assertTrue($this->client->getResponse()->isRedirection());

// ログイン後、パスワードがマイグレーションされていることを確認.
$this->entityManager->clear();
$Member = $this->entityManager->find(Member::class, $Member->getId());

self::assertNotSame($hash, $Member->getPassword(), $hash.':'.$Member->getPassword());
self::assertStringStartsWith('$', $Member->getPassword(), $Member->getPassword());
}
}

0 comments on commit 3e1d7b7

Please sign in to comment.