PDO exception at login submission

6 years ago

paolo
Member | 15
+
0
-

I have aproblem with login.
When I submit the login form I get a PDO exception:
You cannot serialize or unserialize PDO instances.

If I don't delete the session cookie not only my application, but all Nette examples fail to work and show an error page with the same exception (generated by session_start() call).

These are the last calls (as showed by the debug page, but in reverse order):

UserAccessPresenter.php:

public function loginFormSubmitted($form)
{
    try
    {
        $values = $form->getValues();
        if ($values->remember)
            $this->user->setExpiration('+ 14 days', FALSE);
        else
            $this->user->setExpiration('+ 20 minutes', TRUE);
>>>>>>>     $this->user->login($values->username, $values->password);
        $this->flashMessage('Hello, '.$values->username.'. You are now logged in');
        $this->restoreRequest($this->backlink);
        $this->redirect('Homepage:default');
    }

Nette/Security/User.php:

public function login($id = NULL, $password = NULL)
{
    $this->logout(TRUE);
    if (!$id instanceof IIdentity) {
        $credentials = func_get_args();
        $id = $this->getAuthenticator()->authenticate($credentials);
    }
    $this->storage->setIdentity($id);
>>>>>>  $this->storage->setAuthenticated(TRUE);
    $this->onLoggedIn($this);
}

Nette/Http/UserStorage.php

public function setAuthenticated($state)
{
    $section = $this->getSessionSection(TRUE);
    $section->authenticated = (bool) $state;

    // Session Fixation defence
>>>>>>  $this->sessionHandler->regenerateId();

    if ($state) {
        $section->reason = NULL;
        $section->authTime = time(); // informative value

Nette/Http/Session.php:

public function regenerateId()
{
    if (self::$started && !$this->regenerated) {
        if (headers_sent($file, $line)) {
            throw new Nette\InvalidStateException("Cannot regenerate session ID after HTTP headers have been sent" . ($file ? " (output started at $file:$line)." : "."));
        }
        session_regenerate_id(TRUE);
>>>>>>>     session_write_close();
        $backup = $_SESSION;
        session_start();
        $_SESSION = $backup;
    }
    $this->regenerated = TRUE;
}

inner-code PDO→ __sleep ()

6 years ago

paolo
Member | 15
+
0
-

Solved!
In the Authenticator class, I passed to the Identity constructor an instance of GroupedSelection (returned by the related() method of class ActiveRow) instead of an array.
Being not particularly expert of PHP, I thought that, because GroupedSelection implements the interface ArrayAccess, could also be converted in array by cast (used in Identity constructor). In fact it was converted, but not the way I expected. The conversion was performed as for any other class, including all class members, among which there must be some references to PDO objects.
Being such Identity included in the session store, it is subject to serialization/unserialization, and this is the reason of the exception.

I hope this could help someone else with similar problems.

public function authenticate(array $credentials)
{
    list($username, $password) = $credentials;
    $row = $this->database->table('user')->where('username', $username)->fetch();

    if (!$row) {
        throw new NS\AuthenticationException("User '$username' not found.", self::IDENTITY_NOT_FOUND);
    }

    if ($row->password !== $this->calculateHash($password)) {
        throw new NS\AuthenticationException("Invalid password.", self::INVALID_CREDENTIAL);
    }

    unset($row->password);

>>>>    $roles = $row->related('user_role', 'user_id');
    return new NS\Identity($row->id, $roles, $row->toArray());
}