Symfony2 security token cleared after redirect - security

I have built a login form, with a custom provider which successfully sets the auth token.
I can see the "logged in as" in the profiler, while on the redirect interception page. The form then redirects to my success page.
For some reason, my success page, doesn't recognise that I'm logged in and loops back to the login page.
security:
encoders:
EP\Common\Entity\User: sha1
encode_as_base64: false
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
main:
entity: { class EP\Common\Entity\User, property: username }
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login_form:
pattern: ^/cms/(login|logout)$
security: false
cms:
pattern: ^/cms/
security: true
provider: main
form_login:
check_path: /cms/login_check
login_path: /cms/login
logout:
path: /cms/logout
target: /cms/login
access_control:
- { path: ^/cms/login, roles: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: http }
- { path: /cms, roles: ROLE_USER }

I've discovered why this is.
I'd added these methods to my User class (notice the [0] on unserialize - doctrine was looking for the ID of the user based on the first character of the ID):
/**
* (PHP 5 >= 5.1.0)<br/>
* String representation of object
* #link http://php.net/manual/en/serializable.serialize.php
* #return string the string representation of the object or null
*/
public function serialize()
{
return serialize($this->getId());
}
/**
* (PHP 5 >= 5.1.0)<br/>
* Constructs the object
* #link http://php.net/manual/en/serializable.unserialize.php
* #param string $serialized <p>
* The string representation of the object.
* </p>
* #return mixed the original value unserialized.
*/
public function unserialize($serialized)
{
$this->_uuid = unserialize($serialized)[0];
}

Related

Two Login in Symfony 6

I had problems with tow login in Symfony 6. When I access to /admin/login I get the error "Class App\Controller\AuthenticationUtils does not exist"
here is my security.yaml
security:
encoders:
App\Entity\User:
algorithm: auto
App\Entity\AdminUser:
algorithm: auto
enable_authenticator_manager: true
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
App\Entity\User:
algorithm: auto
App\Entity\AdminUser:
algorithm: auto
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
providers:
# used to reload user from session & other features (e.g. switch_user)
app_user_provider:
entity:
class: App\Entity\User
property: email
admin_user_provider:
entity:
class: App\Entity\AdminUser
property: email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
admin:
pattern: ^/admin
lazy: true
provider: admin_user_provider
custom_authenticator: App\Security\AdminLoginFormAuthenticator
logout:
path: admin_logout
# where to redirect after logout
# TODO target: app_any_route
main:
lazy: true
provider: app_user_provider
custom_authenticator: App\Security\LoginFormAuthenticator
logout:
path: app_logout
# where to redirect after logout
# TODO target: app_any_route
# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#the-firewall
# https://symfony.com/doc/current/security/impersonating_user.html
# switch_user: true
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
# TODO - { path: ^/admin, roles: ROLE_ADMIN }
# TODO - { path: ^/profile, roles: ROLE_USER }
And it is my AdminSecurityController.php
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class AdminSecurityController extends AbstractController
{
/**
* #Route("/admin/security", name="admin_security")
*/
public function index(): Response
{
return $this->render('admin_security/index.html.twig', [
'controller_name' => 'AdminSecurityController',
]);
}
/**
* #Route("/admin/login", name="admin_login")
*/
public function login(AuthenticationUtils $authenticationUtils): Response
{
// get the login error if there is one
// $error = $authenticationUtils->getLastAuthenticationError();
// // last username entered by the user
// $lastUsername = $authenticationUtils->getLastUsername();
return $this->render('admin_login/index.html.twig'); //, ['last_username' => $lastUsername, 'error' => $error]
}
/**
* #Route("/admin/logout", name="admin_logout")
*/
public function logout()
{
throw new \Exception('This method can be blank - it will be intercepted by the logout key on your firewall');
}
}
I attach some images with information about the error
I have no idea about the problem, hope you can help me!!
Thank you !!
You're missing your import of the
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
at the top of your controller

Symfony 4.4 Security / Session is saved but not used

Full config files are available bellow.
My website is using 2 guards at differents entries :
lexik_jwt_authentication.jwt_token_authenticator to access the ^/api routes
App\Security\LoginAuthenticator to access ^/secured routes
The JWT authetification is working well, allowing users to call a API plateform routes such as localhost/api/types
The problem is about using the LoginAuthenticator session. This is the basic symfony configuration (auto-generated files with php bin/console make:auth)
When login with correct user/password, the guard save a session to app/var/sessions/dev/sess_ras4up86e1c8a1bs9khr5t7scg
When the session is saved and set, the LoginAuthenticator trigger onAuthenticationSuccess function redirecting the user to route name `test.
But the testController is not working, redirecting the user to login page (302 HTTP code). It also throwing the following error in var/log/dev/dev.log :
[2021-07-08 13:07:40] request.INFO: Matched route "app_login". {"route":"app_login","route_parameters":{"_route":"app_login","_controller":"App\\Controller\\SecurityController::login"},"request_uri":"https://krang.local/login","method":"POST"} []
[2021-07-08 13:07:40] security.DEBUG: Checking for guard authentication credentials. {"firewall_key":"login","authenticators":1} []
[2021-07-08 13:07:40] security.DEBUG: Checking support on guard authenticator. {"firewall_key":"login","authenticator":"App\\Security\\LoginAuthenticator"} []
[2021-07-08 13:07:40] security.DEBUG: Calling getCredentials() on guard authenticator. {"firewall_key":"login","authenticator":"App\\Security\\LoginAuthenticator"} []
[2021-07-08 13:07:40] security.DEBUG: Passing guard token information to the GuardAuthenticationProvider {"firewall_key":"login","authenticator":"App\\Security\\LoginAuthenticator"} []
[2021-07-08 13:07:40] doctrine.DEBUG: SELECT t0.id AS id_1, t0.username AS username_2, t0.password AS password_3, t0.is_active AS is_active_4, t0.roles AS roles_5, t0.customer_id AS customer_id_6 FROM users t0 WHERE t0.username = ? LIMIT 1 ["matthieu"] []
[2021-07-08 13:07:40] security.INFO: Guard authentication successful! {"token":"[object] (Symfony\\Component\\Security\\Guard\\Token\\PostAuthenticationGuardToken: PostAuthenticationGuardToken(user=\"matthieu\", authenticated=true, roles=\"ROLE_USER, ROLE_ADMIN\"))","authenticator":"App\\Security\\LoginAuthenticator"} []
[2021-07-08 13:07:40] security.DEBUG: Guard authenticator set success response. {"response":"[object] (Symfony\\Component\\HttpFoundation\\RedirectResponse: HTTP/1.0 302 Found\r\nCache-Control: no-cache, private\r\nDate: Thu, 08 Jul 2021 11:07:40 GMT\r\nLocation: /secured/backmarketProducts\r\n\r\n<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"UTF-8\" />\n <meta http-equiv=\"refresh\" content=\"0;url='/secured/backmarketProducts'\" />\n\n <title>Redirecting to /secured/backmarketProducts</title>\n </head>\n <body>\n Redirecting to /secured/backmarketProducts.\n </body>\n</html>)","authenticator":"App\\Security\\LoginAuthenticator"} []
[2021-07-08 13:07:40] security.DEBUG: Remember me skipped: it is not configured for the firewall. {"authenticator":"App\\Security\\LoginAuthenticator"} []
[2021-07-08 13:07:40] security.DEBUG: The "App\Security\LoginAuthenticator" authenticator set the response. Any later authenticator will not be called {"authenticator":"App\\Security\\LoginAuthenticator"} []
[2021-07-08 13:07:40] request.INFO: Matched route "test". {"route":"test","route_parameters":{"_route":"test","_controller":"App\\Controller\\BackMarketController::productsList"},"request_uri":"https://krang.local/secured/backmarketProducts","method":"GET"} []
[2021-07-08 13:07:40] security.DEBUG: Checking for guard authentication credentials. {"firewall_key":"secured","authenticators":1} []
[2021-07-08 13:07:40] security.DEBUG: Checking support on guard authenticator. {"firewall_key":"secured","authenticator":"App\\Security\\LoginAuthenticator"} []
[2021-07-08 13:07:40] security.DEBUG: Guard authenticator does not support the request. {"firewall_key":"secured","authenticator":"App\\Security\\LoginAuthenticator"} []
[2021-07-08 13:07:40] security.INFO: An AuthenticationException was thrown; redirecting to authentication entry point. {"exception":"[object] (Symfony\\Component\\Security\\Core\\Exception\\AuthenticationCredentialsNotFoundException(code: 0): A Token was not found in the TokenStorage. at /home/matthieu/krang/webservice/vendor/symfony/security-http/Firewall/AccessListener.php:69)"} []
[2021-07-08 13:07:40] security.DEBUG: Calling Authentication entry point. [] []
[2021-07-08 13:07:40] request.INFO: Matched route "app_login". {"route":"app_login","route_parameters":{"_route":"app_login","_controller":"App\\Controller\\SecurityController::login"},"request_uri":"https://krang.local/login","method":"GET"} []
[2021-07-08 13:07:40] security.DEBUG: Checking for guard authentication credentials. {"firewall_key":"login","authenticators":1} []
[2021-07-08 13:07:40] security.DEBUG: Checking support on guard authenticator. {"firewall_key":"login","authenticator":"App\\Security\\LoginAuthenticator"} []
[2021-07-08 13:07:40] security.DEBUG: Guard authenticator does not support the request. {"firewall_key":"login","authenticator":"App\\Security\\LoginAuthenticator"} []
[2021-07-08 13:07:40] security.INFO: Populated the TokenStorage with an anonymous Token. [] []
[2021-07-08 13:07:40] request.INFO: Matched route "_wdt". {"route":"_wdt","route_parameters":{"_route":"_wdt","_controller":"web_profiler.controller.profiler::toolbarAction","token":"ad25b7"},"request_uri":"https://krang.local/_wdt/ad25b7","method":"GET"} []
We can see this error :
[2021-07-08 13:07:40] security.DEBUG: Guard authenticator does not support the request. {"firewall_key":"secured","authenticator":"App\\Security\\LoginAuthenticator"} []
[2021-07-08 13:07:40] security.INFO: An AuthenticationException was thrown; redirecting to authentication entry point. {"exception":"[object] (Symfony\\Component\\Security\\Core\\Exception\\AuthenticationCredentialsNotFoundException(code: 0): A Token was not found in the TokenStorage. at /home/matthieu/krang/webservice/vendor/symfony/security-http/Firewall/AccessListener.php:69)"} []
Guard authenticator does not support the request
What does this mean ? I give you some useful code to checkout :
security.yaml : (full file)
security:
encoders:
App\Entity\User:
algorithm: auto
role_hierarchy:
ROLE_USER : "ROLE_USER"
ROLE_ADMIN : "ROLE_ADMIN"
ROLE_SUPERADMIN : "ROLE_SUPERADMIN"
providers:
entity_provider:
entity:
class: App\Entity\User
property: username
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login:
pattern: ^/login
stateless: true
anonymous: true
json_login:
check_path: /login_check
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
guard:
authenticators:
- App\Security\LoginAuthenticator
logout:
path: app_logout
# where to redirect after logout
# target: app_any_route
docs:
pattern: ^/docs
stateless: true
anonymous: true
secured:
pattern: ^/secured
stateless: true
provider: entity_provider
guard:
authenticators:
- App\Security\LoginAuthenticator
api:
pattern: ^/api
stateless: true
anonymous: false
provider: entity_provider
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
- { path: ^/docs, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/secured, roles: IS_AUTHENTICATED_FULLY }
SecurityController: (unchanged from default)
class SecurityController extends AbstractController
{
/**
* #Route("/login", name="app_login")
*/
public function login(AuthenticationUtils $authenticationUtils): Response
{
if ($this->getUser()) {
die();
}
// get the login error if there is one
$error = $authenticationUtils->getLastAuthenticationError();
// last username entered by the user
$lastUsername = $authenticationUtils->getLastUsername();
return $this->render('security/login.html.twig', ['last_username' => $lastUsername, 'error' => $error]);
}
/**
* #Route("/logout", name="app_logout")
*/
public function logout()
{
throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
}
}
LoginAuthenticator: (src/Security/LoginAuthenticator.php)
class LoginAuthenticator extends AbstractFormLoginAuthenticator implements PasswordAuthenticatedInterface
{
use TargetPathTrait;
public const LOGIN_ROUTE = 'app_login';
private $entityManager;
private $urlGenerator;
private $csrfTokenManager;
private $passwordEncoder;
public function __construct(EntityManagerInterface $entityManager, UrlGeneratorInterface $urlGenerator, CsrfTokenManagerInterface $csrfTokenManager, UserPasswordEncoderInterface $passwordEncoder)
{
$this->entityManager = $entityManager;
$this->urlGenerator = $urlGenerator;
$this->csrfTokenManager = $csrfTokenManager;
$this->passwordEncoder = $passwordEncoder;
}
public function supports(Request $request)
{
return self::LOGIN_ROUTE === $request->attributes->get('_route')
&& $request->isMethod('POST');
}
public function getCredentials(Request $request)
{
$credentials = [
'username' => $request->request->get('username'),
'password' => $request->request->get('password'),
'csrf_token' => $request->request->get('_csrf_token'),
];
$request->getSession()->set(
Security::LAST_USERNAME,
$credentials['username']
);
return $credentials;
}
public function getUser($credentials, UserProviderInterface $userProvider)
{
$token = new CsrfToken('authenticate', $credentials['csrf_token']);
if (!$this->csrfTokenManager->isTokenValid($token)) {
throw new InvalidCsrfTokenException();
}
$user = $this->entityManager->getRepository(User::class)->findOneBy(['username' => $credentials['username']]);
if (!$user) {
throw new UsernameNotFoundException('Username could not be found.');
}
return $user;
}
public function checkCredentials($credentials, UserInterface $user)
{
return $this->passwordEncoder->isPasswordValid($user, $credentials['password']);
}
/**
* Used to upgrade (rehash) the user's password automatically over time.
*/
public function getPassword($credentials): ?string
{
return $credentials['password'];
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
return new RedirectResponse($targetPath);
}
return new RedirectResponse($this->urlGenerator->generate('test'));
}
protected function getLoginUrl()
{
return $this->urlGenerator->generate(self::LOGIN_ROUTE);
}
}
BackMarketController (just a function)
function called on authentification success
/**
* #return JsonResponse
* #Route("/secured/backmarketProducts", name="test")
*/
public function productsList(Request $request)
{
return $this->render('back_market/backmarketProducts.html.twig');
}
About the webserver :
Apache2
Debian 8
using HTTPS
Symfony 4.4
I can give you more informations of course, just ask for it.
What i tried by looking on other similar subjects :
Symfony 4 login Guard authenticator errors (save the session information elsewhere from default)
update project components
Symfony 4 login form : authenticating successfully, but authentication immediately lost after redirect (add EquatableInterface to User entity)
Kill onAuthenticationSuccess BEFORE REDIRECTION show on the profiler that a session is created but cant follow redirection (look at the error above)
UPDATE 1 (3 days later)
I found a way to allow jwt token and securityauthentificator to work together.
There is the security.yaml :
security:
encoders:
App\Entity\User:
algorithm: auto
role_hierarchy:
ROLE_USER : "ROLE_USER"
ROLE_ADMIN : "ROLE_ADMIN"
ROLE_SUPERADMIN : "ROLE_SUPERADMIN"
providers:
entity_provider:
entity:
class: App\Entity\User
property: username
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: true
guard:
entry_point: lexik_jwt_authentication.jwt_token_authenticator
authenticators:
- App\Security\SecurityAuthenticator
- lexik_jwt_authentication.jwt_token_authenticator
logout:
path: app_logout
json_login:
check_path: /login_check
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
login:
pattern: ^/login
stateless: true
anonymous: true
json_login:
check_path: /login_check
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
docs:
pattern: ^/docs
stateless: true
anonymous: true
api:
pattern: ^/api
stateless: true
anonymous: false
provider: entity_provider
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
secured:
pattern: ^/secured
anonymous: false
guard:
authenticators:
- App\Security\SecurityAuthenticator
logout:
path: app_logout
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
- { path: ^/docs, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/secured, roles: IS_AUTHENTICATED_FULLY }
I think that block solve the issue, the symfony security compenent got both guards declared on main firewall, using jwt by default.
To use the basic symfony auth system (securityAuthentificator) i just added a secured firewall providing SecurityAuthenticator
Is there a good way to work with security ? Does this trick seems legit ? Im not sure im providing a good solution.
Nobody seems able to help me. In any case I solved the problem on my own.
There is my full functionnal security.yaml :
This config is working, making symfony able to use API PLATEFORM with JWT tokens and to log user on a simple back office application.
security:
encoders:
App\Entity\User:
algorithm: auto
role_hierarchy:
ROLE_USER : "ROLE_USER"
ROLE_ADMIN : "ROLE_ADMIN"
ROLE_SUPERADMIN : "ROLE_SUPERADMIN"
providers:
entity_provider:
entity:
class: App\Entity\User
property: username
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: true
guard:
entry_point: lexik_jwt_authentication.jwt_token_authenticator
authenticators:
- App\Security\SecurityAuthenticator
- lexik_jwt_authentication.jwt_token_authenticator
logout:
path: app_logout
json_login:
check_path: /login_check
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
login:
pattern: ^/login
stateless: true
anonymous: true
json_login:
check_path: /login_check
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
docs:
pattern: ^/docs
stateless: true
anonymous: true
api:
pattern: ^/api
stateless: true
anonymous: false
provider: entity_provider
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
secured:
pattern: ^/secured
anonymous: false
guard:
authenticators:
- App\Security\SecurityAuthenticator
logout:
path: app_logout
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
- { path: ^/docs, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/secured, roles: IS_AUTHENTICATED_FULLY }

Error while unserializing user data in symfony authentication

my first question here. I have been sitting on it for few hours and couldn't find solution:
The error pops out when the user is successfuly found in DB and i guess symfony tries to serialize it's data into session.
Notice: unserialize(): Error at offset 37 of 49 bytes in G:\cebuland\vendor\symfony\symfony\src\Symfony\Component\Security\Core\Authentication\Token\AbstractToken.php line 163
Causes login process faliure.
User's Entity:
/**
* #ORM\Entity
* #ORM\Table(name="User")
*/
class User implements AdvancedUserInterface, \Serializable{
...
/**
* #ORM\ManyToMany(targetEntity="Role", inversedBy="user")
* #var $role Doctrine\Common\Collections\ArrayCollection
*/
private $role;
...
public function getRoles() {
return $this->role->toArray();
}
...
public function serialize() {
serialize(array(
$this->id,
$this->name,
$this->password,
$this->created,
$this->last_activity,
$this->ghost,
$this->role
));
}
public function unserialize($serialized) {
list(
$this->id,
$this->name,
$this->password,
$this->created,
$this->last_activity,
$this->ghost,
$this->role
) = unserialize($serialized);
}
Role's Entity is quite similiar.
And the security.yml configuration file:
security:
providers:
users:
entity: {class: ApplicationMainBundle:User, property: name}
encoders:
Application\MainBundle\Entity\User:
#plain just for testing
algorithm: plaintext
firewalls:
secured_area:
logout:
path: /logout
pattern: ^/
anonymous: ~
form_login:
login_path: /login
check_path: /login_check
access_control:
- { path: ^/admin/, roles: ROLE_ADMINISTRATOR}
Couldn't find a clue anywhere on the internet.
Your User::serialize method does not return serialized string, but it should Serializable::serialize

How to change Symfony2 security plaintext encoders from User to User Interface

I'm trying to crate a chain provider for login form in my Symfony2 application (version 2.3) - this is my security Yaml:
jms_security_extra:
secure_all_services: false
expressions: true
security:
encoders:
Symfony\Component\Security\Core\User\User: plaintext
FOS\UserBundle\Model\UserInterface: sha512
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
chain_provider:
chain:
providers: [in_memory, fos_userbundle]
fos_userbundle:
id: fos_user.user_provider.username
in_memory:
memory:
users:
admin: { password: god, roles: [ 'ROLE_ADMIN' ] }
firewalls:
main:
pattern: ^/
form_login:
provider: chain_provider
csrf_provider: form.csrf_provider
logout: true
anonymous: true
security: true
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
#- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/, role: ROLE_ADMIN }
- { path: ^/group/, role: ROLE_ADMIN }
As you can see, I'm using FOSUserBundle (great stuff btw).
The problem is that after I login with in_memory admin user, I can't get to the /profile/ URL. I'm getting this error msg:
AccessDeniedHttpException: This user does not have access to this section
I found a cause to this - the problem is in FOS\UserBundle\Controller\ProfileController class:
public function showAction()
{
$user = $this->container->get('security.context')->getToken()->getUser();
if (!is_object($user) || !$user instanceof UserInterface) {
throw new AccessDeniedException('This user does not have access to this section.');
}
return $this->container->get('templating')->renderResponse('FOSUserBundle:Profile:show.html.'.$this->container->getParameter('fos_user.template.engine'), array('user' => $user));
}
The Controller is checking if $user object is an instance of UserInterface, which is not, because it is instance of Symfony\Component\Security\Core\User\User (plaintext encoder class).
I tried to change encoder configuration to this:
security:
encoders:
Symfony\Component\Security\Core\User\UserInterface: plaintext
But it didn't work. I found that the User class is hardcoded in numerous places with the Symfony engine.
So my question is: how to change that behaviour from security yaml? Am I missing something?
PHP documentation:
instanceof is smart enough to know that a class that implements an
interface is an instance of the interface
Symfony\Component\Security\Core\User\UserInterface implements AdvancedUserInterface which implements UserInterface.
Your problem is not the typeof check in FOS\UserBundle\Controller\ProfileController but a wrong firewall configuration or the in-memory user not receiving it's roles correctly!
Sorry, but you cant see the profile of memory user's. Profile is made only for FOS users. Thats why it must implement FOS\UserBundle\Model\UserInterface.

Symfony2 Security log user manually

I want to log user manually in Symfony2. (I use fosuserbundle).
The authentication will be triggered in custom route like this /login/auto
Here is my controller code which match with /login/auto
public function loginAction(){
$em = $this->container->get('doctrine')->getManager();
$users = $em->getRepository('MybundleMainBundle:User');
$user = $users->findOneByEmail("user#user.com");
$securityContext = $this->get('security.context');
$token = new UsernamePasswordToken($user, null, 'main', $user->getRoles());
$securityContext->setToken($token);
$this->get('session')->set('_security_'.'main', serialize($token));
return new RedirectResponse($this->generateUrl('home'));
}
But after the redirection, I'm redirected automatically to /login and not /home so the authentification failed
Here is my security file config :
security:
providers:
fos_userbundle:
id: fos_user.user_provider.username
encoders:
FOS\UserBundle\Model\UserInterface: sha512
firewalls:
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_provider: form.csrf_provider
always_use_default_target_path: true
logout: true
anonymous: true
switch_user: true
remember_me:
key: %secret%
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
access_control:
- { path: ^/login, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, role: ROLE_USER }
role_hierarchy:
ROLE_USER: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
Thanks for your help
Looks very similar to mine. Maybe you should not write into the session. Or the token needs the (hashed) password. Try it, here's a working code ;)
public function demologinAction(Request $request)
{
$dm = $this->get('doctrine.odm.mongodb.document_manager');
$repo = $dm->getRepository('AcmeUserBundle:User');
$user = $repo->findOneByUsername('demo');
if (!$user) {
throw $this->createNotFoundException('No demouser found!');
}
$token = new UsernamePasswordToken($user, $user->getPassword(), 'main', $user->getRoles());
$context = $this->get('security.context');
$context->setToken($token);
$router = $this->get('router');
$url = $router->generate('dashboard_show');
return $this->redirect($url);
}
Why are you trying to log a user in manually?
I may be wrong, but if the reason is so that you can run some postLogin code, it would be easier to use the built in login functionality, but setup a listener on the login action as a service. Then add your login code in there.
Sevice definition would be:
user.login:
class: You\Bundle\EventListener\EventListener
arguments: [#doctrine.orm.entity_manager, #service_container]
tags:
- { name: kernel.event_listener, event: security.interactive_login, method: onLogin }
And your event listener might be:
public function onLogin(InteractiveLoginEvent $event)
{
$user = $event->getAuthenticationToken()->getUser();
$user->setLastLoggedInAt(new \DateTime());
$user->setLoginCount($user->getLoginCount() + 1);
$this->manager->flush();
}

Resources