Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony2 - Security Role - From PHP 5.3 to PHP >5.4 - getRole() on a non-object

I already had a look at this issue : https://github.com/symfony/symfony/issues/3691

My problem is that I can't find a solution to make it work.

I use Symfony 2.8.3

Here is the error I had :

FatalErrorException in RoleHierarchy.php line 43: Error: Call to a member function getRole() on a non-object

I serialized everything properly, here are my classes :

User

<?php
/**
 */

namespace CNAMTS\PHPK\SecurityBundle\Security\User;

use Symfony\Component\Security\Core\User\UserInterface;
use CNAMTS\PHPK\SecurityBundle\Security\Role;

/**
 * Classe abstraite implémentant la classe Symfony UserInterface.
 */
abstract class User implements UserInterface
{
    public function __construct() {
        $this->roles = array();
    }

    /**
     * Concaténation du nom et du numéro d'agent : NOM-NUMERO.
     *
     * @var String
     */
    protected $ismum;
    /**
     * Nom de l'utilisateur.
     *
     * @var String
     */
    protected $nom;
    /**
     * Prénom de l'utilisateur.
     *
     * @var String
     */
    protected $prenom;
    /**
     * Id de l'utilisateur.
     *
     * @var String
     */
    protected $id;
    /**
     * Numéro d'agent.
     *
     * @var String
     */
    protected $chrono;
    /**
     * Code de l'organisme
     *
     * @var String
     */
    protected $codeOrganisme;
    /**
     * Numéro Siret de l'organisme.
     *
     * @var String
     */
    protected $siret;
    /**
     * Services AccessMaster de l'utilisateur.
     *
     * @var array(Symfony\Component\Security\Core\Role\Role)
     */
    protected $roles;
    /**
     * Système de l'utilisateur.
     *
     * @var String
     */
    protected $systeme;

    /**
     * Défini l'Ismum (Concaténation du nom et du numéro d'agent : NOM-NUMERO).
     *
     * @param String $ismum
     */
    public function setIsmum($ismum)
    {
        $this->ismum = $ismum;
    }
    /**
     * Retourne l'Ismum (Concaténation du nom et du numéro d'agent : NOM-NUMERO).
     *
     * @return String
     */
    public function getIsmum()
    {
        return $this->ismum;
    }
    /**
     * Défini le nom de l'utilisateur.
     *
     * @param String $nom
     */
    public function setNom($nom)
    {
        $this->nom = $nom;
    }
    /**
     * Retourne le nom de l'utilisateur.
     *
     * @return String
     */
    public function getNom()
    {
        return $this->nom;
    }
    /**
     * Défini le prénom de l'utilisateur.
     *
     * @param String $prenom
     */
    public function setPrenom($prenom)
    {
        $this->prenom = $prenom;
    }
    /**
     * Retourne le nom de l'utilisateur.
     *
     * @return String
     */
    public function getPrenom()
    {
        return $this->prenom;
    }
    /**
     * Défini l'id de l'utilisateur.
     *
     * @param String $id
     */
    public function setId($id)
    {
        $this->id = $id;
    }
    /**
     * Retourne l'id de l'utilisateur.
     *
     * @return String
     */
    public function getId()
    {
        return $this->id;
    }
    /**
     * Défini le numéro d'agent.
     *
     * @param String $chrono
     */
    public function setChrono($chrono)
    {
        $this->chrono = $chrono;
    }
    /**
     * Retourne le numéro d'agent.
     *
     * @return String
     */
    public function getChrono()
    {
        return $this->chrono;
    }
    /**
     * Défini le code organisme
     * @param String $codeOrganisme
     */
    public function setCodeOrganisme($codeOrganisme)
    {
        $this->codeOrganisme = $codeOrganisme;
    }
    /**
     * Retourne le code organisme
     * @return String
     */
    public function getCodeOrganisme()
    {
        return $this->codeOrganisme;
    }
    /**
     * Défini le SIRET de l'utilisateur.
     *
     * @param String $siret
     */
    public function setSiret($siret)
    {
        $this->siret = $siret;
    }
    /**
     * Retourne le SIRET de l'utilisateur.
     *
     * @return String
     */
    public function getSiret()
    {
        return $this->siret;
    }

    /**
     * Ajoute un service AccessMaster à l'utilisateur.
     *
     * @param String $role
     */
    public function addRole(Role $role)
    {
        $this->roles[] = $role;
    }
    /**
     * Retourne les services AccessMaster de l'utilisateur.
     *
     * @return array(CNAMTS\PHPK\SecurityBundle\Security\Role)
     */
    public function getRoles()
    {
        return $this->roles;
    }

    /**
     * Défini le système de l'utilisateur.
     *
     * @param String $systeme
     */
    public function setSysteme($systeme)
    {
        $this->systeme = $systeme;
    }
    /**
     * Retourne le système de l'utilisateur.
     *
     * @return String
     */
    public function getSysteme()
    {
        return $this->systeme;
    }

    /**
     * @ignore
     */
    public function eraseCredentials()
    {
    }

    /**
     * Permet de tester si deux instances de UserInterface sont égales.
     *
     * @param UserInterface $user
     *
     * @return boolean
     */
    public function equals(UserInterface $user)
    {
        if (!$user instanceof User) {
            return false;
        }

        if ($this->username !== $user->getUsername()) {
            return false;
        }
        if ($this->organisme !== $user->getOrganisme()) {
            return false;
        }
        if ($this->jeton !== $user->getJeton()) {
            return false;
        }

        return true;
    }

    /**
     * Retourne true si l'utilisateur possède le service passé en paramètre
     * Prend en paramètre une chaîne ou un tableau de chaînes.
     *
     * @param mixed $role
     *
     * @return boolean
     */
    public function isGranted($role)
    {
        if (is_array($role)) {
            foreach ($role as $r) {
                foreach ($this->getRoles() as $own) {
                    if ($own->getRole() === $r) {
                        return true;
                    }
                }
            }
        } elseif (is_string($role)) {
            foreach ($this->getRoles() as $own) {
                if ($own->getRole() === $role) {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * @ignore
     */
    public function getUsername()
    {
        return $this->getIsmum();
    }
    /**
     * @ignore
     */
    public function getPassword()
    {
        return;
    }
    /**
     * @ignore
     */
    public function getSalt()
    {
        return;
    }
}

Implementation of this abstract user

<?php
namespace CNAMTS\PHPK\SecurityBundle\Security\User;

/**
 * Classe décrivant un User lorsque le mode AccessMaster pour la sécurité est activé.
 */
class AccessMasterUser extends User implements \Serializable
{
    public function serialize()
    {
        return \json_encode(array(
            $this->civilite,
            $this->chrono,
            $this->codeOrganisme,
            $this->id,
            $this->ismum,
            $this->nom,
            $this->prenom,
            serialize($this->roles),
            $this->siret,
            $this->systeme
        ));
    }
    public function unserialize($serialized)
    {
        list(
            $this->civilite,
            $this->chrono,
            $this->codeOrganisme,
            $this->id,
            $this->ismum,
            $this->nom,
            $this->prenom,
            $roles,
            $this->siret,
            $this->systeme
        ) = \json_decode($serialized);

        $this->roles = unserialize($roles);
    }

    /**
     * Civilité de l'utilisateur.
     *
     * @var String
     */
    private $civilite;

    /**
     * Défini la civilité de l'utilisateur.
     *
     * @param String $civilite
     */
    public function setCivilite($civilite)
    {
        $this->civilite = $civilite;
    }
    /**
     * Retourne la civilité de l'utilisateur.
     *
     * @return String
     */
    public function getCivilite()
    {
        return $this->civilite;
    }
}

Role

<?php
namespace CNAMTS\PHPK\SecurityBundle\Security;

use Symfony\Component\Security\Core\Role\RoleInterface;

class Role implements RoleInterface, \Serializable
{
    private $role;
    private $attributes;

    public function serialize() {
        return \json_encode(array(
            $this->role,
            $this->attributes
        ));
    }

    public function unserialize($serialized) {
        list(
            $this->role,
            $this->attributes
        ) = \json_decode($serialized);
    }

    /**
     * Constructor.
     *
     * @param string $role The role name
     */
    public function __construct($role, $attributes = array())
    {
        $this->role = (string) $role;
        $this->attributes = $attributes;
    }

    /**
     * {@inheritdoc}
     */
    public function getRole()
    {
        return $this->role;
    }

    /**
     * {@inheritdoc}
     */
    public function getAttributes()
    {
        return $this->attributes;
    }
}

Just after the login, all roles are ok, users.roles and roles are exactly the same :

First page

But when I go to another page, I got this :

Second page

What is wrong in my code ? Why is this working on PHP 5.3.3, but doesn't work on PHP 5.4.40 or PHP 5.5.28 ?

Thanks in advance, I'm totally blocked.

like image 692
Ulti Avatar asked Jul 19 '16 11:07

Ulti


1 Answers

I think the answer to your problem is in that linked bug, as GitHub user Sharom points out here and here.

So it seems that problem is that you're including User::$roles into the serialization/unserialization of the User class itself when you don't have to.

P.S. I also think it's weird and probably improper that you're using json_*() as the mechanism behind the Serializable interface.

like image 95
Peter Bailey Avatar answered Nov 15 '22 09:11

Peter Bailey