0

I have Token entity that store api_key and have one-to-one relation to User entity :

AppBundle\Entity\Token:
    type: entity
    table: null

    oneToOne:
        user:
            targetEntity: User

    id:
        id:
            type: integer
            id: true
            generator:
                strategy: AUTO
    fields:
        apiKey:
            type: string
            length: 255
        dateCreated:
            type: datetime
            column: date_created
        dateExpired:
            type: datetime
            column: date_expired

I'm using simple_preauth listener for login. When login is successful, I call TokenGenerator service on my login page:

public function loginAction()
    {
        $user = $this->get('security.token_storage')->getToken()->getUser();

        if ($user instanceof User) {
            $apiKey = $this->get('app_bundle.token_generator')->createApiKey()->getApiKey();
            return new Response($apiKey);
        }

        throw new AuthenticationException('Authentication failed');

    }

TokenGenerator returns api key, that I can use for authentication on another pages. But also this service save api_key into Token table:

use Doctrine\ORM\EntityRepository as TokenRepository;
use Doctrine\ORM\EntityManager;
use AppBundle\Entity\Token;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;

class TokenGenerator
{
    private $user;

    public function __construct(
        EntityManager $em, 
        TokenRepository $tokenRepository, 
        TokenStorageInterface $tokenStorage
    ) {
        $this->em = $em;
        $this->tokenRepository = $tokenRepository;
        $this->tokenStorage = $tokenStorage;
    }

    public function getApiKey()
    {
        return $this->apiKey;
    }

    public function createApiKey()
    {
        $this->apiKey = password_hash(
            uniqid(mt_rand(), true), PASSWORD_DEFAULT, array('cost' => '10')
        );

        $this->user = $this->tokenStorage->getToken()->getUser();
        $currentApiKey = $this->tokenRepository->findOneBy(array('user' => $this->user));

        if ($currentApiKey) {
            $this->em->remove($currentApiKey);
            $this->em->flush();
        }

        $this->saveApiKey();

        return $this;
    }

    private function saveApiKey()
    {
        $token = new Token();
        $dateCreated = new \DateTime("now");
        $dateExpired = new \DateTime($dateCreated->format("Y/m/d H:i:s") . "+1 day");

        $token->setApiKey($this->apiKey);
        $token->setDateCreated($dateCreated);
        $token->setDateExpired($dateExpired);
        $token->setUser($this->user);

        $this->em->persist($token);
        $this->em->flush();

    }

}

But when I call $this->saveApiKey() I have strange bug: my User password in database become empty.

When I debugged this issue, I notice, that salt not recreated after password disappearing.

I also tried to remove one-to-one relation, (update db and clear cache, of course), but even Token table has no relation to User, I got changing password to empty after saving Token to db.

When $this->saveApiKey() not call, all is OK.

Please, help me to catch this weird bug. Thanks a lot for any help!

Sergio Ivanuzzo
  • 1,820
  • 4
  • 29
  • 59
  • 1
    I see you get an existing token when getting a User: $this->user = $this->tokenStorage->getToken()->getUser(); Why do you instantiate a new token inside of saveApiKey() method? – Đuro Mandinić Dec 01 '15 at 13:33
  • @DjuroMandinic `$this->tokenStorage->getToken()` returns authentication token, `saveApiKey()` method need to save `api_key` into db. **Token** just my entity name there. – Sergio Ivanuzzo Dec 01 '15 at 13:39
  • @DjuroMandinic btw, thank you for useful comment, I have edited my `TokenGenerator` code and added `use` statements. – Sergio Ivanuzzo Dec 01 '15 at 13:42
  • 1
    I would check if the relation Token to User is actually defined as unidirectional. If not, perhaps setting a Token to User is missing. I'm also thinking that if a User would have an association to your Token entity (unidirectional), you would not have to use "persist". Just "flush". I think the persist causes the problem here. – Đuro Mandinić Dec 01 '15 at 13:52
  • @DjuroMandinic relation **Token** to **User** is unidirectional. I removed `persist()`, so Token not saved to db, but password become empty. It seems problem with `flush()`. – Sergio Ivanuzzo Dec 01 '15 at 13:57
  • @DjuroMandinic I tried to search after this and found [this answer](http://stackoverflow.com/a/9248128/5397119), and then I have found my problem. I have incorrect `eraseCredentials()` into my User entity class. – Sergio Ivanuzzo Dec 01 '15 at 14:00
  • @DjuroMandinic thanks a lot! problem was solved! – Sergio Ivanuzzo Dec 01 '15 at 14:00
  • Another pair of eyes is often useful :) – Đuro Mandinić Dec 01 '15 at 14:02
  • 1
    Be careful about changing eraseCredentials. You may end up storing the password in your session file which could be a bad thing. – Cerad Dec 01 '15 at 14:50

1 Answers1

0

SOLVED. I had incorrect eraseCredentials(), so my password became null.

See also my another question, from which I have started to change my authentication system.

Community
  • 1
  • 1
Sergio Ivanuzzo
  • 1,820
  • 4
  • 29
  • 59