I am having some trouble with login and authentication in Symfony2. The exception is "$user must be an instanceof UserInterface, an object implementing a __toString method, or a primitive string."
Debugging my code I could notice that the user I am trying to log in my application can get authenticated successfully (app/log/dev.log) but the credentials var is null:
The user variable from AbstractToken has the user data from database.
I continue debugging in the ContextListener->refreshUser function and I get these values:
Everything has the value null and on the Symfony\Bridge\Doctrine\Security\User\EntityUserProvider->refreshUser function returns the variable $refreshedUser as null, so when the function $token->setUser($refreshedUser) on the ContextListener class fails and throws the exception.
I write down my security.yml and my entities I am using:
security.yml:
security:
encoders:
Pladuch\BackBundle\Entity\BaseUser:
algorithm: sha512
encode_as_base64: false
iterations: 1
providers:
sga:
entity: { class: 'PladuchBackBundle:Usuario', property: username }
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
sga:
pattern: ^/gestion
anonymous: ~
form_login:
login_path: pladuch_login_sga
check_path: pladuch_login_check
default_target_path: pladuch_sga_index
csrf_provider: form.csrf_provider
provider: sga
logout:
path: pladuch_logout_sga
target: pladuch_login_sga
access_control:
- { path: ^/gestion/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/gestion, roles: ROLE_ADMIN }
Abstract class BaseUser:
<?php
namespace Pladuch\BackBundle\Entity;
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
abstract class BaseUser implements AdvancedUserInterface, \Serializable
{
protected $id;
protected $salt;
protected $username;
protected $password;
public function __construct()
{
$this->isActive = true;
$this->salt = $this->generateSalt();
}
public function serialize()
{
return serialize(array($this->id, $this->username, $this->password));
}
public function unserialize($serialized)
{
list($this->id, $this->username, $this->password) = unserialize($serialized);
}
public function getRoles()
{
return array('ROLE_ADMIN');
}
public function getPassword()
{
return $this->password;
}
public function setPassword($password)
{
$this->password = $password;
}
public function getUsername()
{
return $this->username;
}
public function eraseCredentials()
{
}
public function setSalt($salt)
{
$this->salt = $salt;
return $this;
}
public function getSalt()
{
return $this->salt;
}
public function generateSalt()
{
return base_convert(sha1(uniqid(mt_rand(), true)), 16, 36);
}
public function isAccountNonExpired()
{
return true;
}
public function isAccountNonLocked()
{
return true;
}
public function isCredentialsNonExpired()
{
return true;
}
public function isEnabled()
{
return true;
}
}
Class Usuario:
<?php
namespace Pladuch\BackBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Usuario
*
* #ORM\Table(name="usuario",
* uniqueConstraints={
* #ORM\UniqueConstraint(name="username", columns={"username"})
* },
* indexes={#ORM\Index(name="FK_USUARIO_ROL", columns={"rol_id"})})
* #ORM\Entity(repositoryClass="Pladuch\BackBundle\Repository\UsuarioRepository")
*/
class Usuario extends BaseUser
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id()
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #var string
*
* #ORM\Column(name="username", type="string", length=255, nullable=false)
*/
protected $username;
/**
* #var string
*
* #ORM\Column(name="password", type="string", length=1024, nullable=false)
*/
protected $password;
/**
* #var string
*
* #ORM\Column(name="salt", type="string", length=1024, nullable=false)
*/
protected $salt;
/**
* #var string
*
* #ORM\Column(name="email", type="string", length=255, nullable=false)
*/
protected $email;
/**
* #var Rol
*
* #ORM\ManyToOne(targetEntity="Rol", inversedBy="id")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="rol_id", referencedColumnName="id")
* })
*/
protected $rol;
/**
* #var bool
*
* #ORM\Column(name="activo", type="boolean", nullable=true)
*/
protected $activo = true;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set username
*
* #param string $username
* #return Usuario
*/
public function setUsername($username)
{
$this->username = $username;
return $this;
}
/**
* Get username
*
* #return string
*/
public function getUsername()
{
return $this->username;
}
/**
* Set password
*
* #param string $password
* #return Usuario
*/
public function setPassword($password)
{
$this->password = $password;
return $this;
}
/**
* Get password
*
* #return string
*/
public function getPassword()
{
return $this->password;
}
/**
* Set salt
*
* #param string $salt
* #return Usuario
*/
public function setSalt($salt)
{
$this->salt = $salt;
return $this;
}
/**
* Get salt
*
* #return string
*/
public function getSalt()
{
return $this->salt;
}
/**
* Set email
*
* #param string $email
* #return Usuario
*/
public function setEmail($email)
{
$this->email = $email;
return $this;
}
/**
* Get email
*
* #return string
*/
public function getEmail()
{
return $this->email;
}
/**
* Set rol
*
* #param Rol $rol
* #return Usuario
*/
public function setRol(Rol $rol = null)
{
$this->rol = $rol;
return $this;
}
/**
* Get rol
*
* #return Rol
*/
public function getRol()
{
return $this->rol;
}
/**
* #return array|\Symfony\Component\Security\Core\Role\Role[]
*/
public function getRoles()
{
return array($this->getRol()->getRol());
}
/**
* Set activo
*
* #param $activo
* #return $this
*/
public function setActivo($activo)
{
$this->activo = $activo;
return $this;
}
/**
* Get activo
*
* #return bool
*/
public function getActivo()
{
return $this->activo;
}
}
The UsuarioRepository where I implements the three functions loadUserByUsername, refreshUser and supportsClass:
class UsuarioRepository extends EntityRepository implements UserProviderInterface
{
public function loadUserByUsername($username)
{
$q = $this->createQueryBuilder('u')
->where('u.username = :username')
->setParameter('username', $username)
->getQuery();
try {
$user = $q->getSingleResult();
} catch (NoResultException $e) {
$message = sprintf('Unable to find an active Usuario object identified by %s', $username);
throw new UsernameNotFoundException($message, 0, $e);
}
return $user;
}
public function refreshUser(UserInterface $userInterface)
{
$class = get_class($userInterface);
if (! $this->supportsClass($class)) {
throw new UnsupportedUserException(sprintf('Instances of %s are not suppoted', $class));
}
}
public function supportsClass($class)
{
return $this->getEntityName() === $class || is_subclass_of($class, $this->getEntityName());
}
}
Thank you for your help.
Kind regards.
P.S: I am using Symfony 2.5.6
Ok, I forgot to add the return sentence on refreshUser function in my repository...
return $this->find($userInterface->getId());
or
return $userInterface;
$userInterface has the authenticated user so I didn't need the $this->find() method. That solved everything
Related
Impossible to create a new event, I always get 415 error
I test with postman, if I test the same endpoint with ParamConverter annotation, I can reach the function.
So the error should come from configuration
Here is my controller
<?php
namespace App\Controller;
use App\Entity\Event;
use FOS\RestBundle\Controller\AbstractFOSRestController;
use FOS\RestBundle\View\View;
use Symfony\Component\HttpFoundation\Response;
use FOS\RestBundle\Controller\Annotations as Rest;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Component\Validator\ConstraintViolationListInterface;
/**
* Event controller.
* #Route("/api", name="api_")
*/
class EventController extends AbstractFOSRestController
{
/**
* Create New Event
* #Rest\Post("/event/create")
* #param Event $event
* #param ConstraintViolationListInterface $violations
* #ParamConverter("event", converter="fos_rest.request_body")
* #throws
* #return View
*/
public function createAction(Event $event, ConstraintViolationListInterface $violations)
{
if (count($violations)) {
return View::create($violations, Response::HTTP_BAD_REQUEST);
}
$em = $this->getDoctrine()->getManager();
$em->persist($event);
$em->flush();
return View::create($event, Response::HTTP_OK);
}
}
This is Fost Rest configuration, I checked the documentation and it should be ok
# Read the documentation: https://symfony.com/doc/master/bundles/FOSRestBundle/index.html
fos_rest:
routing_loader:
default_format: json
include_format: false
body_listener: true
format_listener:
rules:
- { path: '^/', priorities: ['json'], fallback_format: json, prefer_extension: false }
param_fetcher_listener: true
access_denied_listener:
json: true
view:
view_response_listener: 'force'
formats:
json: true
body_converter:
enabled: true
validate: true
validation_errors_argument: violations
And to finish, event entity
<?php
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints\DateTime;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity
* #ORM\Table(name="event")
*/
class Event
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\User")
*
*/
protected $organizer;
/**
* #ORM\Column(type="text")
* #Assert\NotBlank
*/
protected $title;
/**
* #ORM\Column(type="text")
*/
protected $description;
/**
* #ORM\Column(type="text")
*/
protected $address;
/**
* #ORM\Column(type="text")
*/
protected $city;
/**
* #ORM\Column(type="text")
*/
protected $postCode;
/**
* #ORM\Column(type="text")
*/
protected $coverPicture;
/**
* #ORM\Column(type="float")
*/
protected $price;
/**
* #ORM\Column(type="integer")
*/
protected $maxAttendees;
/**
* #ORM\Column(type="datetime")
*/
protected $dateFrom;
/**
* #ORM\Column(type="datetime")
*/
protected $dateTo;
/**
* #ORM\Column(type="integer")
*/
protected $status;
/**
* #ORM\Column(type="boolean")
*/
protected $featured;
/**
* List of attendees
* #ORM\ManyToMany(targetEntity="User")
* #ORM\JoinTable(name="event_atendees",
* joinColumns={#ORM\JoinColumn(name="event_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="attendee_id", referencedColumnName="id")}
* )
*/
protected $attendees;
public function __construct()
{
$this->attendees = new ArrayCollection();
}
/**
* #return int
*/
public function getId() : int
{
return $this->id;
}
/**
* #param int $id
* #return Event
*/
public function setId(int $id)
{
$this->id = $id;
return $this;
}
/**
* #return User
*/
public function getOrganizer() : User
{
return $this->organizer;
}
/**
* #param User $organizer
* #return Event
*/
public function setOrganizer(User $organizer)
{
$this->organizer = $organizer;
return $this;
}
/**
* #return string
*/
public function getTitle() : string
{
return $this->title;
}
/**
* #param string $title
* #return Event
*/
public function setTitle(string $title)
{
$this->title = $title;
return $this;
}
/**
* #return string
*/
public function getDescription() : string
{
return $this->description;
}
/**
* #param string $description
* #return Event
*/
public function setDescription(string $description)
{
$this->description = $description;
return $this;
}
/**
* #return string
*/
public function getAddress() : string
{
return $this->address;
}
/**
* #param string $address
* #return Event
*/
public function setAddress(string $address)
{
$this->address = $address;
return $this;
}
/**
* #return string
*/
public function getCity() : string
{
return $this->city;
}
/**
* #param string $city
* #return Event
*/
public function setCity(string $city)
{
$this->city = $city;
return $this;
}
/**
* #return string
*/
public function getPostCode() : string
{
return $this->postCode;
}
/**
* #param string $postCode
* #return Event
*/
public function setPostCode(string $postCode)
{
$this->postCode = $postCode;
return $this;
}
/**
* #return string
*/
public function getCoverPicture() : string
{
return $this->coverPicture;
}
/**
* #param string $coverPicture
* #return Event
*/
public function setCoverPicture(string $coverPicture)
{
$this->coverPicture = $coverPicture;
return $this;
}
/**
* #return float
*/
public function getPrice() : float
{
return $this->price;
}
/**
* #param float $price
* #return Event
*/
public function setPrice(float $price)
{
$this->price = $price;
return $this;
}
/**
* #return int
*/
public function getMaxAttendees() : int
{
return $this->maxAttendees;
}
/**
* #param int $maxAttendees
* #return Event
*/
public function setMaxAttendees(int $maxAttendees)
{
$this->maxAttendees = $maxAttendees;
return $this;
}
/**
* #return DateTime
*/
public function getDateFrom() : DateTime
{
return $this->dateFrom;
}
/**
* #param DateTime $dateFrom
* #return Event
*/
public function setDateFrom(DateTime $dateFrom)
{
$this->dateFrom = $dateFrom;
return $this;
}
/**
* #return DateTime
*/
public function getDateTo() : DateTime
{
return $this->dateTo;
}
/**
* #param DateTime $dateTo
* #return Event
*/
public function setDateTo(DateTime $dateTo)
{
$this->dateTo = $dateTo;
return $this;
}
/**
* #return int
*/
public function getStatus() : int
{
return $this->status;
}
/**
* #param int $status
* #return Event
*/
public function setStatus(int $status)
{
$this->status = $status;
return $this;
}
/**
* #return bool
*/
public function getFeatured() : bool
{
return $this->featured;
}
/**
* #param bool $featured
* #return Event
*/
public function setFeatured(bool $featured)
{
$this->featured = $featured;
return $this;
}
/**
* #return User[]
*/
public function getAttendees() : ArrayCollection
{
return $this->attendees;
}
/**
* #param User[] $attendees
* #return Event
*/
public function setAttendees($attendees)
{
$this->attendees = $attendees;
return $this;
}
/**
* #param User $attendee
*/
public function addAttendee(User $attendee) {
$this->attendees->add($attendee);
}
/**
* #param User $attendee
*/
public function removeAttendee(User $attendee) {
$this->attendees->removeElement($attendee);
}
}
Is somebody have an idea ?
I have made login form with Security Guide. When I try to login I have logs like below:
2019-06-10 10:16:56] security.INFO: User has been authenticated successfully. {"username":"user#example.com"} []
[2019-06-10 10:16:56] security.DEBUG: Stored the security token in the session. {"key":"_security_main"} []
[2019-06-10 10:16:56] request.INFO: Matched route "app_user_dashboard". {"route":"app_user_dashboard","route_parameters":{"_route":"app_user_dashboard","_controller":"App\\Controller\\User\\UserController::dashboard"},"request_uri":"https://127.0.0.1:8001/app/dashboard","method":"GET"} []
[2019-06-10 10:16:56] security.DEBUG: Read existing security token from the session. {"key":"_security_main","token_class":"Symfony\\Component\\Security\\Core\\Authentication\\Token\\UsernamePasswordToken"} []
[2019-06-10 10:16:57] doctrine.DEBUG: SELECT t0.id AS id_1, t0.password AS password_2, t0.email AS email_3, t0.first_name AS first_name_4, t0.last_name AS last_name_5, t0.username AS username_6, t0.referral_code AS referral_code_7, t0.referred_by_code AS referred_by_code_8, t0.roles AS roles_9, t0.active_to AS active_to_10, t0.created_at AS created_at_11, t0.updated_at AS updated_at_12 FROM users t0 WHERE t0.id = ? [15] []
[2019-06-10 10:16:57] security.DEBUG: Cannot refresh token because user has changed. {"username":"user#example.com","provider":"Symfony\\Bridge\\Doctrine\\Security\\User\\EntityUserProvider"} []
[2019-06-10 10:16:57] security.DEBUG: Token was deauthenticated after trying to refresh it. [] []
and also I use EquatableInterface. My User.php code:
namespace App\Entity\User;
use DateTime;
use Doctrine\ORM\Mapping as ORM;
use Exception;
use Serializable;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\EquatableInterface;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* Class User
*
* #ORM\Table(name="users")
* #ORM\Entity(repositoryClass="App\Repository\User\UserRepository")
* #ORM\HasLifecycleCallbacks
*
* #ORM\Entity
* #UniqueEntity(fields="username", message="username taken")
* #UniqueEntity(fields="email", message="email taken")
*/
class User implements UserInterface, Serializable, EquatableInterface
{
/**
* #var int
*
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(type="string", length=256)
*/
private $password;
/**
* #var string
*
* #ORM\Column(type="string", length=64, unique=true)
*/
private $email;
/**
* #var string|null
*
* #ORM\Column(type="string", length=64, nullable=true)
*/
private $firstName;
/**
* #var string|null
*
* #ORM\Column(type="string", length=64, nullable=true)
*/
private $lastName;
/**
* #var string
*
* #ORM\Column(type="string", length=64, unique=true)
*/
private $username;
/**
* #var string
*
* #ORM\Column(type="string", length=64, unique=true)
*/
private $referralCode;
/**
* #var string|null
*
* #ORM\Column(type="string", length=64, nullable=true)
*/
private $referredByCode;
/**
* #var array
*
* #ORM\Column(type="array", length=64)
*/
private $roles;
/**
* #var DateTime
*
* #ORM\Column(type="datetime")
*/
private $activeTo;
/**
* #var DateTime
*
* #ORM\Column(type="datetime")
*/
private $createdAt;
/**
* #var DateTime
*
* #ORM\Column(type="datetime", nullable=true)
*/
private $updatedAt;
/**
* User constructor.
*
* #throws Exception
*/
public function __construct()
{
$this->createdAt = new DateTime();
$this->updatedAt = new DateTime();
$this->activeTo = new DateTime('now + 14 days');
$this->referralCode = substr(hash('sha256', uniqid()), 0, 5);
}
/**
* #return string
*/
public function __toString()
{
return $this->getUsername();
}
/**
* #return int
*/
public function getId(): int
{
return $this->id;
}
/**
* #param string $username
*/
public function setUsername(string $username): void
{
$this->username = $username;
}
/**
* #return string
*/
public function getUsername(): ?string
{
return $this->username;
}
/**
* #return null|string
*/
public function getSalt(): ?string
{
// you *may* need a real salt depending on your encoder
// see section on salt below
return null;
}
/**
* #return string
*/
public function getPassword(): ?string
{
return $this->password;
}
/**
* #param string $password
*/
public function setPassword(string $password)
{
$this->password = $password;
}
/**
* #return array
*/
public function getRoles(): array
{
// return $this->roles;
return ['ROLE_USER', 'ROLE_API_USER'];
}
/**
*
*/
public function eraseCredentials()
{
}
/**
* #see Serializable::serialize()
*/
public function serialize()
{
return serialize(array($this->id, $this->email));
}
/**
* #see Serializable::unserialize()
*
* #param $serialized
*/
public function unserialize($serialized)
{
list ($this->id, $this->email) = unserialize($serialized, array('allowed_classes' => false));
}
/**
* #return string
*/
public function getEmail(): ?string
{
return $this->email;
}
/**
* #param string $email
*/
public function setEmail(string $email): void
{
$this->email = $email;
}
/**
* #return DateTime
*/
public function getCreatedAt(): DateTime
{
return $this->createdAt;
}
/**
* #ORM\PrePersist
*
* #throws Exception
*/
public function setCreatedAt(): void
{
$this->createdAt = new DateTime();
}
/**
* #return DateTime
*/
public function getUpdatedAt(): DateTime
{
return $this->updatedAt;
}
/**
* #ORM\PreUpdate
*
* #throws Exception
*/
public function setUpdatedAt(): void
{
$this->updatedAt = new DateTime();
}
/**
* #return DateTime
*/
public function getActiveTo(): DateTime
{
return $this->activeTo;
}
/**
* #param DateTime $activeTo
*/
public function setActiveTo(DateTime $activeTo): void
{
$this->activeTo = $activeTo;
}
/**
* #return string
*/
public function getReferralCode(): string
{
return $this->referralCode;
}
/**
* #param string $referralCode
*/
public function setReferralCode(string $referralCode): void
{
$this->referralCode = $referralCode;
}
/**
* #return string|null
*/
public function getReferredByCode():? string
{
return $this->referredByCode;
}
/**
* #param string|null $referredByCode
*/
public function setReferredByCode(?string $referredByCode): void
{
$this->referredByCode = $referredByCode;
}
/**
* #return string|null
*/
public function getFirstName(): ?string
{
return $this->firstName;
}
/**
* #param string|null $firstName
*/
public function setFirstName(?string $firstName): void
{
$this->firstName = $firstName;
}
/**
* #return string|null
*/
public function getLastName(): ?string
{
return $this->lastName;
}
/**
* #param string|null $lastName
*/
public function setLastName(?string $lastName): void
{
$this->lastName = $lastName;
}
/**
* #param array $roles
*/
public function setRoles(array $roles): void
{
$this->roles = $roles;
}
/**
* The equality comparison should neither be done by referential equality
* nor by comparing identities (i.e. getId() === getId()).
*
* However, you do not need to compare every attribute, but only those that
* are relevant for assessing whether re-authentication is required.
*
* #param UserInterface $user
*
* #return bool
*/
public function isEqualTo(UserInterface $user)
{
if ($this->username !== $user->getUsername()) {
return false;
}
return true;
}
}
and security.yaml
encoders:
App\Entity\User\User:
algorithm: auto
providers:
user_provider:
entity:
class: App\Entity\User\User
property: username
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
http_basic: ~
anonymous: true
# logout_on_user_change: true
provider: user_provider
form_login:
login_path: app_user_login
check_path: app_user_login
default_target_path: app_user_dashboard
csrf_token_generator: security.csrf.token_manager
logout:
path: /app/logout
target: /app/login
# activate different ways to authenticate
# http_basic: true
# https://symfony.com/doc/current/security.html#a-configuring-how-your-users-will-authenticate
# form_login: true
# https://symfony.com/doc/current/security/form_login_setup.html
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
- { path: ^/app/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/app/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/app, roles: IS_AUTHENTICATED_FULLY }
I have red this post: Token was deauthenticated after trying to refresh it and that solution does not work for me. Any ideas?
You've got 2 options here:
Make your firewall stateless or
update your serialization in you User
I'm referring to https://symfony.com/doc/current/security/user_provider.html#understanding-how-users-are-refreshed-from-the-session btw, as I had the same issue.
First solution:
firewalls:
# ...
main:
http_basic: ~
anonymous: true
stateless: true
This should make Symfony ignore your serialization and just reload the whole entity from database.
Second solution:
class User implements UserInterface, Serializable, EquatableInterface
{
public function serialize()
{
return serialize(array(
$this->id,
$this->password,
$this->email,
$this->username,
$this->activeTo,
));
}
public function unserialize($serialized)
{
list (
$this->id,
$this->password,
$this->email,
$this->username,
$this->activeTo,
) = unserialize($serialized, array('allowed_classes' => false));
}
}
You should keep any information that Symfony might need in any of your user_checker classes (or the default ones).
First of all, don't bother to copy this code. This will be available on my github soon. (I'll update this post just in case someone will need it)
Hi. I'm trying to use Steam to connect in my application. So, I've tried to create a custom user provider and a custom authentication. After I click Log In button, my user (I've added one by myself) is loaded from database and I'm redirected to my custom page. In that page, my debug toolbar is telling me that I'm authenticated with my custom Token and Firewall. If I move to another page, "/search" for example, my debug toolbar is telling me that I'm not authenticated anymore...
What am I doing wrong?
I'm using Symfony 4.0.6. Thank you !
P.S.: This script is inspired by this one: https://github.com/SirWaddles/SteamAuthBundle
P.P.S: If I missed any file and you need it, please reply.
P.P.P.S: I think it's a problem with serialize() and unserialize(), but I don't know exactly.
Player.php
<?php
namespace App\Entity;
use App\Service\SteamAuth\User\SteamUserInterface;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
use Symfony\Component\Security\Core\User\EquatableInterface;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* Class Player
* #package App\Entity
*
* #ORM\Entity(repositoryClass="App\Repository\PlayerRepository")
* #ORM\Table(name="players")
*/
class Player implements UserInterface, SteamUserInterface, AdvancedUserInterface, EquatableInterface, \Serializable
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*
* #var int
*/
private $id;
/**
* #ORM\Column(type="string", length=255, )
*
* #var string
*/
private $username;
/**
* #ORM\Column(type="string", length=255)
*
* #var string
*/
private $name;
/**
* #ORM\Column(type="string", length=255)
*
* #var string
*/
private $password;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*
* #var null|string
*/
private $avatar;
/**
* #var array
*
* #ORM\Column(type="array")
*/
private $roles;
/**
* #var \DateTime|null
*
* #ORM\Column(type="datetime", nullable=true)
*/
private $lastSync;
/**
* #var bool
*
* #ORM\Column(type="boolean")
*/
private $enabled;
/**
* #return int
*/
public function getId(): int
{
return $this->id;
}
/**
* #param int $id
*
* #return Player
*/
public function setId(int $id): Player
{
$this->id = $id;
return $this;
}
/**
* #return string
*/
public function getUsername(): string
{
return $this->username;
}
/**
* #param string $username
*
* #return Player
*/
public function setUsername(string $username): Player
{
$this->username = $username;
return $this;
}
/**
* #return string
*/
public function getName(): string
{
return $this->name;
}
/**
* #param string $name
*
* #return Player
*/
public function setName(string $name): Player
{
$this->name = $name;
return $this;
}
/**
* #return string
*/
public function getPassword()
{
return $this->password;
}
/**
* #return array
*/
public function getRoles()
{
return $this->roles;
}
/**
* #param array $roles
* #return Player
*/
public function setRoles(array $roles): Player
{
$this->roles = $roles;
return $this;
}
/**
* #return \DateTime|null
*/
public function getLastSync(): ?\DateTime
{
return $this->lastSync;
}
/**
* #param \DateTime|null $lastSync
* #return Player
*/
public function setLastSync(?\DateTime $lastSync): Player
{
$this->lastSync = $lastSync;
return $this;
}
/**
* #return null|string
*/
public function getSalt()
{
return null;
}
/**
* #param string $password
* #return Player
*/
public function setPassword(string $password): Player
{
$this->password = $password;
return $this;
}
/**
* #return null|string
*/
public function getAvatar(): ?string
{
return $this->avatar;
}
/**
* #param null|string $avatar
*
* #return Player
*/
public function setAvatar(?string $avatar): Player
{
$this->avatar = $avatar;
return $this;
}
/**
* {#inheritdoc}
*/
public function eraseCredentials()
{
}
/**
* {#inheritdoc}
*/
public function isAccountNonExpired()
{
return true;
}
/**
* {#inheritdoc}
*/
public function isAccountNonLocked()
{
return true;
}
/**
* {#inheritdoc}
*/
public function isCredentialsNonExpired()
{
return true;
}
/**
* {#inheritdoc}
*/
public function isEnabled()
{
return $this->enabled;
}
/**
* #param bool|null $enabled
* #return Player
*/
public function setEnabled(?bool $enabled): Player
{
$this->enabled = $enabled;
return $this;
}
/**
* {#inheritdoc}
*/
public function isEqualTo(UserInterface $user)
{
if ($this->username !== $user->getUsername()) {
return false;
}
return true;
}
/**
* {#inheritdoc}
*/
public function serialize()
{
return serialize([
$this->id,
$this->username,
$this->name,
$this->avatar,
$this->password,
$this->enabled
]);
}
/**
* {#inheritdoc}
*/
public function unserialize($data)
{
list($this->id, $this->username, $this->name, $this->avatar, $this->password, $this->enabled) = unserialize($data);
}
/**
* #return string
*/
public function __toString()
{
return $this->getUsername() ?? '-';
}
}
SteamToken.php
<?php
namespace App\Service\SteamAuth\Token;
use Symfony\Component\Security\Core\Authentication\Token\AbstractToken;
/**
* Class SteamToken
* #package App\Service\SteamAuth\Token
*/
class SteamToken extends AbstractToken
{
/**
* {#inheritdoc}
*/
public function __construct(array $roles = [])
{
parent::__construct($roles);
$this->setAuthenticated(count($roles) > 0);
}
/**
* {#inheritdoc}
*/
public function setAttributes(array $attributes)
{
foreach ($attributes as $key => $attribute) {
$key = str_replace("openid_", "openid.", $key);
$this->setAttribute($key, $attribute);
}
return $this;
}
/**
* {#inheritdoc}
*/
public function getCredentials()
{
}
/**
* {#inheritdoc}
*/
public function serialize()
{
return serialize([
$this->getUser(),
$this->isAuthenticated(),
$this->getAttributes()
]);
}
/**
* {#inheritdoc}
*/
public function unserialize($data)
{
$data = unserialize($data);
$this->setUser($data[0]);
$this->setAuthenticated($data[1]);
$this->setAttributes($data[2]);
}
}
SteamListener.php
<?php
namespace App\Service\SteamAuth\Firewall;
use App\Service\SteamAuth\Token\SteamToken;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Firewall\ListenerInterface;
/**
* Class SteamListener
* #package App\Service\SteamAuth
*/
class SteamListener implements ListenerInterface
{
/**
* #var TokenStorageInterface
*/
private $tokenStorage;
/**
* #var AuthenticationManagerInterface
*/
private $authentication;
/**
* SteamListener constructor.
*
* #param TokenStorageInterface $tokenStorage
* #param AuthenticationManagerInterface $authentication
*/
public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authentication)
{
$this->tokenStorage = $tokenStorage;
$this->authentication = $authentication;
}
public function handle(GetResponseEvent $event)
{
$request = $event->getRequest();
if($request->get('_route') === 'login_check') {
$token = new SteamToken();
$token->setUser(str_replace("http://steamcommunity.com/openid/id/", "", $request->query->get('openid_claimed_id')));
$token->setAttributes($request->query->all());
try {
$authToken = $this->authentication->authenticate($token);
$this->tokenStorage->setToken($authToken);
return;
} catch (AuthenticationException $exception) {
}
}
$response = new Response();
$response->setStatusCode(Response::HTTP_FORBIDDEN);
$event->setResponse($response);
return;
}
}
SteamProvider.php
<?php
namespace App\Service\SteamAuth\Authentication;
use App\Service\SteamAuth\Token\SteamToken;
use GuzzleHttp\Client;
use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserProviderInterface;
/**
* Class SteamProvider
* #package App\Service\SteamAuth\Provider
*/
class SteamProvider implements AuthenticationProviderInterface
{
/**
* #var UserProviderInterface
*/
private $userProvider;
/**
* #var Client
*/
private $client;
/**
* SteamProvider constructor.
*
* #param UserProviderInterface $userProvider
* #param Client $client
*/
public function __construct(UserProviderInterface $userProvider, Client $client)
{
$this->userProvider = $userProvider;
$this->client = $client;
}
/**
* {#inheritdoc}
*/
public function authenticate(TokenInterface $token)
{
if ($token->getAttribute('openid.ns') !== "http://specs.openid.net/auth/2.0") {
throw new AuthenticationException("Invalid token !");
}
$checkAuth = $token->getAttributes();
$checkAuth['openid.mode'] = 'check_authentication';
$response = $this->client->request('GET', 'login', ['query' => $checkAuth]);
if ((string)$response->getBody() === "ns:http://specs.openid.net/auth/2.0\nis_valid:true\n") {
$user = $this->userProvider->loadUserByUsername($token->getUsername());
$authToken = new SteamToken($user->getRoles());
$authToken->setUser($user);
return $authToken;
}
throw new AuthenticationException("Invalid token !");
}
/**
* {#inheritdoc}
*/
public function supports(TokenInterface $token)
{
return $token instanceof SteamToken;
}
}
SteamUserProvider.php
<?php
namespace App\Service\SteamAuth\User;
use App\Entity\Player;
use App\Service\SteamAuth\SteamUserService;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
/**
* Class SteamUserProvider
* #package App\Service\SteamAuth\User
*/
class SteamUserProvider implements UserProviderInterface
{
/**
* #var EntityManager
*/
private $entityManager;
/**
* #var string
*/
private $userClass;
/**
* #var SteamUserService
*/
private $userService;
/**
* SteamUserProvider constructor.
*
* #param EntityManager $entityManager
* #param SteamUserService $userService
* #param string $userClass
*/
public function __construct(EntityManager $entityManager, SteamUserService $userService, string $userClass)
{
$this->entityManager = $entityManager;
$this->userService = $userService;
$this->userClass = $userClass;
}
/**
* {#inheritdoc}
*/
public function loadUserByUsername($username)
{
$repository = $this->entityManager->getRepository($this->userClass);
$player = $repository->findOneBy(['username' => $username]);
if (!$player) {
/**
* #var $player Player
*/
$player = new $this->userClass();
$player->setUsername($username);
$player->setPassword(md5(random_bytes(15)));
$player->setRoles(['ROLE_USER']);
$player->setEnabled(1);
$player = $this->userService->updateUserEntry($player);
$this->entityManager->persist($player);
$this->entityManager->flush($player);
}
/// if last update....
return $player;
}
/**
* {#inheritdoc}
*/
public function refreshUser(UserInterface $user)
{
if (!$user instanceof SteamUserInterface) {
throw new UnsupportedUserException("User not supported!");
}
return $this->loadUserByUsername($user->getUsername());
}
/**
* {#inheritdoc}
*/
public function supportsClass($class)
{
return $class === $this->userClass;
}
}
services.yaml
services:
...
# Aliases
GuzzleHttp\Client: '#eight_points_guzzle.client.login'
# Log In System
app.steam_user.service:
class: App\Service\SteamAuth\SteamUserService
arguments: ['#eight_points_guzzle.client.steam', '%steam_api_key%']
app.steam_user.provider:
class: App\Service\SteamAuth\User\SteamUserProvider
arguments:
$entityManager: '#doctrine.orm.default_entity_manager'
$userService: '#app.steam_user.service'
$userClass: '%steam_user_class%'
app.steam.provider:
class: App\Service\SteamAuth\Authentication\SteamProvider
arguments:
$userProvider: '#app.steam_user.provider'
$client: '#eight_points_guzzle.client.login'
app.steam.listener:
class: App\Service\SteamAuth\Firewall\SteamListener
security.yaml
security:
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
steamauth:
id: app.steam_user.provider
firewalls:
steam_auth:
pattern: ^/login_check
stateless: true
steam: ~
form_login:
csrf_token_generator: security.csrf.token_manager
remember_me:
secret: '%kernel.secret%'
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/login_check, roles: IS_AUTHENTICATED_ANONYMOUSLY }
EDIT: If I dump($this->get('session')->all()) and that page before refresh, I get this: "_security_steam_auth" => "C:38:"App\Service\SteamAuth\Token\SteamToken":40:{a:4:{i:0;N;i:1;b:0;i:2;a:0:{}i:3;a:0:{}}}"
I had a similar problem.
I had a missing attribute in a my serialization process: isActive
I never understand why, but when this attribute is my serialization/unserialization process, it works fine, and when not, it don't work at all.
here is my source: https://github.com/matthieuleorat/documentManager/blob/master/src/Entity/User.php#L253
The doc: http://symfony.com/doc/current/security/entity_provider.html#security-serialize-equatable
Hope it help.
Do you have module_suhosin7 enabled?
We experienced problems on session with suhosin7 enabled.
In fact it adds some rules on session and cookie management.
If enabled, try and disable it and check if it works.
There is a known issue about session encryption with suhosin7 :
https://github.com/sektioneins/suhosin7/issues/21
This lines in SteamListener.php prevents any other routes to work.
$request = $event->getRequest();
if($request->get('_route') === 'login_check') {
[...]
}
$response = new Response();
$response->setStatusCode(Response::HTTP_FORBIDDEN);
$event->setResponse($response);
Security Firewall handle() function is called each times you navigate to a page, so if you set other pages status as forbidden, you won't be able to navigate on other pages than login.
This should work by removing it. Let me know if problem solved
After a lot of work, I decided to make a research again for a Steam Authentication bundle and I found one for Symfony 4 and I confirm that it works.
Link: https://github.com/knojector/SteamAuthenticationBundle
I am trying to implement a login system with Symfony2. I am implementing the AdvancedUserInterface for my User entity, and keep getting the following error when I try to log in. Any help is appreciated.
Error:
$user must be an instanceof UserInterface, an object implementing a __toString method, or a primitive string.
User Entity:
<?php
namespace Flc\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
use Serializable;
/**
* User
*
* #ORM\Table(name="users")
* #ORM\Entity(repositoryClass="Flc\UserBundle\Entity\UserRepository")
*/
class User implements AdvancedUserInterface, Serializable {
/**
* #var integer
*
* #ORM\Column(name="userId", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $userId;
/**
* #var string
*
* #ORM\Column(name="userEmail", type="string", length=50)
*/
private $userEmail;
/**
* #var string
*
* #ORM\Column(name="userName", type="string", length=20)
*/
private $userName;
/**
* #var string
*
* #ORM\Column(name="userPassword", type="string", length=60)
*/
private $userPassword;
/**
* #var string
*
* #ORM\Column(name="userSalt", type="string", length=60, nullable=true)
*/
private $userSalt;
/**
* #var string
*
* #ORM\Column(name="userFirstName", type="string", length=40)
*/
private $userFirstName;
/**
* #var string
*
* #ORM\Column(name="userLastName", type="string", length=40)
*/
private $userLastName;
/**
* #var string
*
* #ORM\Column(name="userPhone", type="string", length=10)
*/
private $userPhone;
/**
* #var \DateTime
*
* #ORM\Column(name="created", type="datetime")
*/
private $created;
/**
* #var boolean
*
* #ORM\Column(name="isActive", type="boolean")
*/
private $isActive;
/**
* #var array
*
* #ORM\Column(name="roles", type="json_array", nullable=true)
*/
private $roles;
#########################
## GETTER - SETTER FUNCTIONS ##
#########################
/**
* Get userId
*
* #return integer
*/
public function getUserId() {
return $this->userId;
}
/**
* Set userEmail
*
* #param string $userEmail
* #return User
*/
public function setUserEmail($userEmail) {
$this->userEmail = $userEmail;
return $this;
}
/**
* Get userEmail
*
* #return string
*/
public function getUserEmail() {
return $this->userEmail;
}
/**
* Set userName
*
* #param string $userName
* #return User
*/
public function setUserName($userName) {
$this->userName = $userName;
return $this;
}
/**
* Get userName
*
* #return string
*/
public function getUserName() {
return $this->userName;
}
/**
* Set userPassword
*
* #param string $userPassword
* #return User
*/
public function setUserPassword($userPassword) {
$this->userPassword = $userPassword;
return $this;
}
/**
* Get userPassword
*
* #return string
*/
public function getUserPassword() {
return $this->userPassword;
}
/**
* Set userSalt
*
* #param string $userSalt
* #return User
*/
public function setUserSalt($userSalt) {
$this->userSalt = $userSalt;
return $this;
}
/**
* Get userSalt
*
* #return string
*/
public function getUserSalt() {
return $this->userSalt;
}
/**
* Set userFirstName
*
* #param string $userFirstName
* #return User
*/
public function setUserFirstName($userFirstName) {
$this->userFirstName = $userFirstName;
return $this;
}
/**
* Get userFirstName
*
* #return string
*/
public function getUserFirstName() {
return $this->userFirstName;
}
/**
* Set userLastName
*
* #param string $userLastName
* #return User
*/
public function setUserLastName($userLastName) {
$this->userLastName = $userLastName;
return $this;
}
/**
* Get userLastName
*
* #return string
*/
public function getUserLastName() {
return $this->userLastName;
}
/**
* Set userPhone
*
* #param string $userPhone
* #return User
*/
public function setUserPhone($userPhone) {
$this->userPhone = $userPhone;
return $this;
}
/**
* Get userPhone
*
* #return string
*/
public function getUserPhone() {
return $this->userPhone;
}
/**
* Set created
*
* #param \DateTime $created
* #return User
*/
public function setCreated($created) {
$this->created = $created;
return $this;
}
/**
* Get created
*
* #return \DateTime
*/
public function getCreated() {
return $this->created;
}
/**
* Set isActive
*
* #param boolean $isActive
* #return User
*/
public function setIsActive($isActive) {
$this->isActive = $isActive;
return $this;
}
/**
* Get isActive
*
* #return boolean
*/
public function getIsActive() {
return $this->isActive;
}
/**
* Set roles
*
* #param boolean $roles
* #return User
*/
public function setRoles(array $roles) {
$this->roles = $roles;
return $this;
}
#############################################
## USER INTERFACE FUNCTIONS IMPLEMENTATION ##
#############################################
public function getRoles() {
#return $this->roles;
$roles = $this->roles;
$roles[] = 'ROLE_USER';
return array_unique($roles);
}
public function eraseCredentials() {
//will be implemented
}
public function getSalt() {
return $this->getUserSalt();
}
public function getPassword() {
return $this->getUserPassword();
}
public function isAccountNonExpired() {
return true;
}
public function isAccountNonLocked() {
return true;
}
public function isCredentialsNonExpired() {
return true;
}
public function isEnabled() {
return $this->isActive;
}
#####################################################
## SERIALIZABLE INTERFACE FUNCTIONS IMPLEMENTATION ##
#####################################################
public function serialize() {
return serialize(array(
$this->userId,
$this->userName,
$this->userPassword
));
}
public function unserialize($serialized) {
list(
$this->userId,
$this->userName,
$this->userPassword) = unserialize($serialized);
}
}
User Repository:
<?php
namespace Flc\UserBundle\Entity;
use Doctrine\ORM\EntityRepository;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
/**
* UserRepository
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class UserRepository extends EntityRepository implements UserProviderInterface {
public function findOneByUsernameOrEmail($username) {
return $this->createQueryBuilder('u')
->andWhere('u.userName = :username OR u.userEmail = :email')
->setParameter('username', $username)
->setParameter('email', $username)
->getQuery()
->getOneOrNullResult();
}
public function loadUserByUsername($username) {
//$user = $this->findOneByUsernameOrEmail($username);
$user = $this->findOneBy(array("userName"=>$username));
if (!$user) {
throw new UsernameNotFoundException('No user found for ' . $username);
}
return $user;
}
public function refreshUser(UserInterface $user) {
$class = get_class($user);
if (!$this->supportsClass($class)) {
throw new UnsupportedUserException(sprintf(
'Instances of "%s" are not supported.', $class
));
}
if (!$refreshedUser = $this->find($user->getUserId())) {
throw new UsernameNotFoundException(sprintf('User with id %s not found'), json_encode($refreshedUser));
}
}
public function supportsClass($class) {
return $this->getEntityName() === $class || is_subclass_of($class, $this->getEntityName());
}
}
Security YML:
security:
encoders:
Flc\UserBundle\Entity\User: bcrypt
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
flc_users:
entity: { class: FlcUserBundle:User }
firewalls:
secured_area:
pattern: ^/
form_login:
login_path: login_form
check_path: login_check
logout:
path: logout
target: /
anonymous: ~
access_control:
- { path: ^/app, roles: ROLE_USER }
try adding __toString method on your User entity:
public function __toString() {
return (string) $this->getUsername();
}
In User Repository you need to replace :
public function findOneByUsernameOrEmail($username) {
return $this->createQueryBuilder('u')
->andWhere('u.userName = :username OR u.userEmail = :email')
->setParameter('username', $username)
->setParameter('email', $username)
->getQuery()
->getOneOrNullResult();
}
public function loadUserByUsername($username) {
//$user = $this->findOneByUsernameOrEmail($username);
$user = $this->findOneBy(array("userName"=>$username));
if (!$user) {
throw new UsernameNotFoundException('No user found for ' . $username);
}
return $user;
}
with :
public function loadUserByUsername($username)
{
$q = $this
->createQueryBuilder('u')
->where('u.username = :username OR u.email = :email')
->setParameter('username', $username)
->setParameter('email', $username)
->getQuery();
try {
$user = $q->getSingleResult();
} catch (NoResultException $e) {
throw new UsernameNotFoundException(sprintf('Unable to find an active admin AcmeUserBundle:User object identified by "%s".', $username), 0, $e);
}
return $user;
}
Situation:
I'm working on a web service accessed from a native iOS application, I don't need to use web forms, just standard NSURLRequests and ready to use didReceiveAuthenticationChallenge so I can win flexibility if someday there is a web/Android version.
It uses doctrine. For now I don't want to use FOSUserBundle due to I only need email and password, not username.
Right now I can register new users and assign them to one group ('ROLE_USER', created by hand at db but assigned via relationships), so Entities seems to work ok.
Problem:
access to my_site/login and appears http auth web box. But when I type the username (email account) and password the box reappears blank again, checked they are OK.
The code:
security.yml
jms_security_extra:
secure_all_services: false
expressions: true
security:
encoders:
Satori\WarnMeBundle\Entity\User:
algorithm: sha512
encode-as-base64: true
iterations: 10
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
main:
entity: { class: SatoriWarnMeBundle:User }
firewalls:
login:
pattern: ^/login$
http_basic:
realm: "Warn Me App"
access_control:
- { path: /login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: /register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: /.*, roles: IS_AUTHENTICATED_ANONYMOUSLY }
SecurityController
namespace Satori\WarnMeBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Security\Core\SecurityContext;
use Symfony\Component\HttpFoundation\JsonResponse;
use Satori\WarnMeBundle\Entity\User;
class SecurityController extends Controller {
public function loginAction() {
$request = $this->getRequest();
$session = $request->getSession();
$errors = array();
// get the login error if there is one
if ($request->attributes->has(SecurityContext::AUTHENTICATION_ERROR)) {
$authError = $request->attributes->get(
SecurityContext::AUTHENTICATION_ERROR);
if (null != $authError) {
$errors['Authentication Error Key'] = $authError->getMessageKey();
$errors['Authentication Error Data'] = $authError->getMessageData();
}
} else {
$authError = $session->get(SecurityContext::AUTHENTICATION_ERROR);
$session->remove(SecurityContext::AUTHENTICATION_ERROR);
if (null != $authError) {
$errors['Authentication Error Key'] = $authError->getMessageKey();
$errors['Authentication Error Data'] = $authError->getMessageData();
}
}
if ($this->container->get('security.context')->isGranted('IS_AUTHENTICATED_FULLY')) {
$errors[] = 'Fully authenticated';
}
return new JsonResponse(array('name' => $session->get(SecurityContext::LAST_USERNAME),
'error' => $errors));
}
public function validateUser($user) {
//Validar campos
$validator = $this->get('validator');
$errors = $validator->validate($user);
if (count($errors) > 0) {
return $errors;
}
return;
}
public function encodePassword($user, $password) {
$factory = $this->get('security.encoder_factory');
$encoder = $factory->getEncoder($user);
$password = $encoder->encodePassword($password, $user->getSalt());
return $password;
}
public function registerAction() {
$this->getEmailAndPassword();
$errors = array();
//Mirar si existe
$exists = $this->getDoctrine()
->getRepository('SatoriWarnMeBundle:User')
->findByEmail($this->email);
if (!$exists) {
//No existe o vacĂo, validar
$user = new User();
$user->setEmail($this->email);
//Codificar password
$user->setPassword($this->encodePassword($user, $this->password));
$groupsRepository = $this->getDoctrine()->getRepository('SatoriWarnMeBundle:Group');
$group = $groupsRepository->findOneByName('ROLE_USER');
if (!$group) {
$errors[] = "No hay grupo";
} else {
$user->addGroup($group);
}
$validFields = $this->validateUser($user);
if ((count($validFields)) > 0) {
foreach ($validFields as $value) {
$val = $value->getMessage();
$errors[] = $val;
}
} else {
try {
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->persist($group);
$em->flush();
} catch (Exception $e) {
if ($e) {
$errors[] = $e->getMessage();
}
}
return new JsonResponse(array('message' => 'Created'), 201);
}
} else {
$errors[] = 'Ya existe';
}
return new JsonResponse(array('errors' => $errors));
}
private function getEmailAndPassword() {
$request = $this->getRequest();
$content = $request->getContent();
$params = NULL;
if (!empty($content)) {
$params = json_decode($content, true);
}
$this->email = $params['email'];
$this->password = $params['password'];
}
}
?>
User
namespace Satori\WarnMeBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
use Symfony\Component\Security\Core\User\EquatableInterface;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Satori\WarnMeBundle\Entity\User
*
* #ORM\Table(name="Satori_users")
* #ORM\Entity(repositoryClass="Satori\WarnMeBundle\Entity\UserRepository")
*/
class User implements AdvancedUserInterface, \Serializable {
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string", length=32)
*/
private $salt;
/**
* #ORM\Column(type="string", length=40)
*/
private $password;
/**
* #ORM\Column(type="string", length=255, unique=true)
*/
private $email;
/**
* #ORM\Column(name="is_active", type="boolean")
*/
private $isActive;
public function __construct() {
$this->isActive = true;
$this->salt = md5(uniqid(null, true));
$this->groups = new ArrayCollection();
}
/**
* #inheritDoc
*/
public function getUsername() {
return $this->email;
}
/**
* #inheritDoc
*/
public function getSalt() {
return $this->salt;
}
/**
* #inheritDoc
*/
public function getPassword() {
return $this->password;
}
/**
* #inheritDoc
*/
public function eraseCredentials() {
}
/**
* #inheritDoc
*/
public function isEqualTo(UserInterface $user) {
return $this->id === $user->getId();
}
/**
* #see \Serializable::serialize()
*/
public function serialize() {
return serialize(array(
$this->id,
));
}
/**
* #see \Serializable::unserialize()
*/
public function unserialize($serialized) {
list (
$this->id,
) = unserialize($serialized);
}
/**
* Get id
*
* #return integer
*/
public function getId() {
return $this->id;
}
/**
* Set salt
*
* #param string $salt
* #return User
*/
public function setSalt($salt) {
$this->salt = $salt;
return $this;
}
/**
* Set password
*
* #param string $password
* #return User
*/
public function setPassword($password) {
$this->password = $password;
return $this;
}
/**
* Set email
*
* #param string $email
* #return User
*/
public function setEmail($email) {
$this->email = $email;
return $this;
}
/**
* Get email
*
* #return string
*/
public function getEmail() {
return $this->email;
}
/**
* Set isActive
*
* #param boolean $isActive
* #return User
*/
public function setIsActive($isActive) {
$this->isActive = $isActive;
return $this;
}
/**
* Get isActive
*
* #return boolean
*/
public function getIsActive() {
return $this->isActive;
}
public function isAccountNonExpired() {
return true;
}
public function isAccountNonLocked() {
return true;
}
public function isCredentialsNonExpired() {
return true;
}
public function isEnabled() {
return $this->isActive;
}
/**
* #ORM\ManyToMany(targetEntity="Group", inversedBy="users")
*
*/
private $groups;
public function getRoles() {
return $this->groups->toArray();
}
/**
* Add groups
*
* #param \Satori\WarnMeBundle\Entity\Group $groups
* #return User
*/
public function addGroup(\Satori\WarnMeBundle\Entity\Group $groups) {
$this->groups[] = $groups;
return $this;
}
/**
* Remove groups
*
* #param \Satori\WarnMeBundle\Entity\Group $groups
*/
public function removeGroup(\Satori\WarnMeBundle\Entity\Group $groups) {
$this->groups->removeElement($groups);
}
/**
* Get groups
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getGroups() {
return $this->groups;
}
}
UserRepository
/**
* Satori\WarnMeBundle\Entity\User
*
* #ORM\Table(name="Satori_users")
* #ORM\Entity(repositoryClass="Satori\WarnMeBundle\Entity\UserRepository")
*/
class User implements AdvancedUserInterface, \Serializable {
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string", length=32)
*/
private $salt;
/**
* #ORM\Column(type="string", length=40)
*/
private $password;
/**
* #ORM\Column(type="string", length=255, unique=true)
*/
private $email;
/**
* #ORM\Column(name="is_active", type="boolean")
*/
private $isActive;
public function __construct() {
$this->isActive = true;
$this->salt = md5(uniqid(null, true));
$this->groups = new ArrayCollection();
}
/**
* #inheritDoc
*/
public function getUsername() {
return $this->email;
}
/**
* #inheritDoc
*/
public function getSalt() {
return $this->salt;
}
/**
* #inheritDoc
*/
public function getPassword() {
return $this->password;
}
/**
* #inheritDoc
*/
public function eraseCredentials() {
}
/**
* #inheritDoc
*/
public function isEqualTo(UserInterface $user) {
return $this->id === $user->getId();
}
/**
* #see \Serializable::serialize()
*/
public function serialize() {
return serialize(array(
$this->id,
));
}
/**
* #see \Serializable::unserialize()
*/
public function unserialize($serialized) {
list (
$this->id,
) = unserialize($serialized);
}
/**
* Get id
*
* #return integer
*/
public function getId() {
return $this->id;
}
/**
* Set salt
*
* #param string $salt
* #return User
*/
public function setSalt($salt) {
$this->salt = $salt;
return $this;
}
/**
* Set password
*
* #param string $password
* #return User
*/
public function setPassword($password) {
$this->password = $password;
return $this;
}
/**
* Set email
*
* #param string $email
* #return User
*/
public function setEmail($email) {
$this->email = $email;
return $this;
}
/**
* Get email
*
* #return string
*/
public function getEmail() {
return $this->email;
}
/**
* Set isActive
*
* #param boolean $isActive
* #return User
*/
public function setIsActive($isActive) {
$this->isActive = $isActive;
return $this;
}
/**
* Get isActive
*
* #return boolean
*/
public function getIsActive() {
return $this->isActive;
}
public function isAccountNonExpired() {
return true;
}
public function isAccountNonLocked() {
return true;
}
public function isCredentialsNonExpired() {
return true;
}
public function isEnabled() {
return $this->isActive;
}
/**
* #ORM\ManyToMany(targetEntity="Group", inversedBy="users")
*
*/
private $groups;
public function getRoles() {
return $this->groups->toArray();
}
/**
* Add groups
*
* #param \Satori\WarnMeBundle\Entity\Group $groups
* #return User
*/
public function addGroup(\Satori\WarnMeBundle\Entity\Group $groups) {
$this->groups[] = $groups;
return $this;
}
/**
* Remove groups
*
* #param \Satori\WarnMeBundle\Entity\Group $groups
*/
public function removeGroup(\Satori\WarnMeBundle\Entity\Group $groups) {
$this->groups->removeElement($groups);
}
/**
* Get groups
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getGroups() {
return $this->groups;
}
}
Group
/
class Group extends Role
{
/*
* #ORM\Column(name="id", type="integer")
* #ORM\Id()
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(name="name", type="string", length=30)
*/
private $name;
/**
* #ORM\Column(name="role", type="string", length=20, unique=true)
*/
private $role;
/**
* #ORM\ManyToMany(targetEntity="User", mappedBy="groups")
*/
private $users;
public function __construct()
{
$this->users = new ArrayCollection();
}
/**
* #see RoleInterface
*/
public function getRole()
{
return $this->role;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Group
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set role
*
* #param string $role
* #return Group
*/
public function setRole($role)
{
$this->role = $role;
return $this;
}
/**
* Add users
*
* #param \Satori\WarnMeBundle\Entity\User $users
* #return Group
*/
public function addUser(\Satori\WarnMeBundle\Entity\User $users)
{
$this->users[] = $users;
return $this;
}
/**
* Remove users
*
* #param \Satori\WarnMeBundle\Entity\User $users
*/
public function removeUser(\Satori\WarnMeBundle\Entity\User $users)
{
$this->users->removeElement($users);
}
/**
* Get users
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getUsers()
{
return $this->users;
}
}
Misc:
For now just testing /login
I'm doing my internal tests with Advanced Rest Client, so I think it's not a client-side problem. If you need any other code please ask for it.
Thank you very much!!!