I'm working with symfony at backend (api). The authentication process is handled by FosUserBundle, LexikJWTAuthenticationBundle and LdapTools... all works fine.
The problem is when I'm about to get the Authenticated user in a controller or service.
The user is authenticated by the Authorization header, does not exist 401 Exception
$this->container->get('security.token_storage')->getToken()->getUser()//null
$preAuthToken = $this->container->get('security.token_storage')->getToken();
$tmp = $this->container->get('lexik_jwt_authentication.jwt_manager')->decode($preAuthToken);//i can get the username and roles
But the real proble is with the security system
if ($this->isGranted('ROLE_USER')) {
echo 'never gets here!!';
} else {
echo 'always';
}
The security system always fails because the user returned by getUser() is always null.
My question is: the LexikJWTAuthenticationBundle should not inject or replace the current user, token after a successfull authentication?
or should I do it programatically? I dont want to fall in bad practices..
thanks in advance!
security.yml info
security:
encoders:
FOS\UserBundle\Model\UserInterface: bcrypt
LdapTools\Bundle\LdapToolsBundle\Security\User\LdapUser: plaintext
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_ADMIN
providers:
ldap:
id: ldap_tools.security.user.ldap_user_provider
fos_userbundle:
id: fos_user.user_provider.username_email
firewalls:
refresh:
pattern: ^/api/token/refresh
stateless: true
anonymous: true
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
api_login:
pattern: ^/login
stateless: true
provider: fos_userbundle
anonymous: true
form_login:
check_path: /login
require_previous_session: false
username_parameter: username
password_parameter: password
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: AppBundle\Handler\AuthenticationFailureHandler
require_previous_session: false
guard:
authenticators:
- ldap_tools.security.ldap_guard_authenticator
logout: true
api:
pattern: ^/
stateless: true
lexik_jwt: ~
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, role: IS_AUTHENTICATED_FULLY }
Auth. failure handler(just in case)
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
$token = $exception->getToken();
if (is_string($exception->getToken()->getUser())) {
$usuario = $this->container->get('fos_user.user_manager')->findUserByUsername($token->getUsername());
if ($usuario) {
$token = new UsernamePasswordToken($usuario, 'yes', 'public', $usuario->getRoles());
} else {
return $this->container->get('lexik_jwt_authentication.handler.authentication_failure')->onAuthenticationFailure($request, $exception);
}
}
return $this->handleAuthenticationFail($request, $token, $exception);
}
public function handleAuthenticationFail(Request $request, TokenInterface $token, AuthenticationException $exception)
{
$username = $token->getUsername();
$password = $request->get('password');
if ($this->ldapManager->authenticate($username, $password)) {
return $this->container->get('lexik_jwt_authentication.handler.authentication_success')->handleAuthenticationSuccess($token->getUser());
}
return $this->container->get('lexik_jwt_authentication.handler.authentication_failure')->onAuthenticationFailure($request, $exception);
}
Related
I work under a Docker project. Symfony 5.
the registration goes well, I have the user registered in the database
the connection goes well, I get the token
there is a record line in the auth table with the token during the connection
on the other hand the access to a protected route it indicates me that the token is not valid
GET http://localhost:8003/api/users/13
Authorization Bearer ey..............................................................
{
"code": 401,
"message": "Invalid JWT Token"
}
security.yml
security:
encoders:
App\Entity\User:
algorithm: bcrypt
providers:
app_user_provider:
entity:
class: App\Entity\User
property: email
firewalls:
refresh:
pattern: ^/api/token/refresh
stateless: true
anonymous: true
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
doc:
pattern: ^/doc
security: false
login:
pattern: ^/api/login
stateless: true
anonymous: true
json_login:
username_path: email
check_path: /api/login/token
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
user_register:
pattern: ^/api/user/register
stateless: true
anonymous: true
main:
pattern: ^/api
stateless: true
anonymous: false
provider: app_user_provider
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
access_control:
- { path: ^/api/token/refresh, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api/user/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api/, roles: IS_AUTHENTICATED_FULLY }
lexik_jwt_authentication.yaml
lexik_jwt_authentication:
private_key_path: "%kernel.project_dir%/%env(JWT_PRIVATE_KEY_PATH)%"
public_key_path: "%kernel.project_dir%/%env(JWT_PUBLIC_KEY_PATH)%"
pass_phrase: "%env(JWT_PASSPHRASE)%"
token_ttl: 3600 # token TTL in seconds, defaults to 1 hour
user_identity_field: email
clock_skew: 0
encoder:
service: lexik_jwt_authentication.encoder.lcobucci
signature_algorithm: RS256
token_extractors:
authorization_header:
enabled: true
prefix: Bearer
name: Authorization
cookie:
enabled: false
name: BEARER
query_parameter:
enabled: false
name: bearer
I have created the 2 certificates with the right passphrase :
.env
...
JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem
JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
JWT_PASSPHRASE=f8bfe4494b7cf3032d642a3e72dcac53
/config/jwt/private.pem
/config/jwt/public.pem
\vendor\Lexik\Bundle\JWTAuthenticationBundle\Security\Guard\JWTTokenAuthenticator.php
public function getCredentials(Request $request)
{
$tokenExtractor = $this->getTokenExtractor();
if (!$tokenExtractor instanceof TokenExtractorInterface) {
throw new \RuntimeException(sprintf('Method "%s::getTokenExtractor()" must return an instance of "%s".', __CLASS__, TokenExtractorInterface::class));
}
if (false === ($jsonWebToken = $tokenExtractor->extract($request))) {
return;
}
$preAuthToken = new PreAuthenticationJWTUserToken($jsonWebToken);
try {
dump($preAuthToken); // --------------
dump($this->jwtManager->decode($preAuthToken)); // ERROR HERE
// --------------
if (!$payload = $this->jwtManager->decode($preAuthToken)) {
throw new InvalidTokenException('Invalid JWT Token');
}
$preAuthToken->setPayload($payload);
} catch (JWTDecodeFailureException $e) {
if (JWTDecodeFailureException::EXPIRED_TOKEN === $e->getReason()) {
$expiredTokenException = new ExpiredTokenException();
$expiredTokenException->setToken($preAuthToken);
throw $expiredTokenException;
}
throw new InvalidTokenException('Invalid JWT Token', 0, $e);
}
return $preAuthToken;
}
dump($preAuthToken);
JWTTokenAuthenticator.php on line 106:
Lexik\Bundle\JWTAuthenticationBundle\Security\Authentication\Token\PreAuthenticationJWTUserToken {#598
-rawToken: "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyaWQiOjIyLCJ1c2VybmFtZSI6InRvdG8xMUB0b3RvLmZyIiwiaWF0IjoxNjIyMDI3NzQ4fQ.COr_fuXAH8iq3Ecr8mJVIVVdLI6H5zv7419gvQwLy6Q"
-payload: null
-credentials: null
-guardProviderKey: null
-user: null
-roleNames: []
-authenticated: false
-attributes: []
}
it's the right token passed in the request
an error occurs on this line: $this->jwtManager->decode($preAuthToken)
and triggers: new InvalidTokenException('Invalid JWT Token', 0, $e);
Which version are you using of LexikJWTAuthentication ? I guess the latest with symfony 5, you should use param public_key instead of public_key_path : https://github.com/lexik/LexikJWTAuthenticationBundle/blob/master/Resources/doc/1-configuration-reference.md
I have a project with Symfony 5.1 using Lexik JWT v2.8.0, gesdinet jwt refresh token v0.9.1 and my own entity user. I can log in with JWT and get the token, save it in a HttpOnly cookie and use it with the protected APIs successfully.
My web app has some API Rest but it has also pages to browse. So my intention is do it all from API, but also login in the web browser when user obtains a token.
But as api login is stateless, after the success login the web profiler still shows logged in as anon. and I can't get te user from the token. I made a service to get the user from the token, to call it in the controller and send some logged in user data to the front end.
I've got a service from this question. The service I have implemented to get the user is:
use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use UserBundle\Domain\Entity\User;
class UserService
{
private TokenStorageInterface $tokenStorage;
private JWTTokenManagerInterface $jwtManager;
public function __construct( TokenStorageInterface $storage, JWTTokenManagerInterface $jwtManager )
{
$this->tokenStorage = $storage;
$this->jwtManager = $jwtManager;
}
public function getCurrentUser() : ?User
{
$decodedJwtToken = $this->jwtManager->decode($this->tokenStorage->getToken());
if ($decodedJwtToken instanceof TokenInterface) {
$user = $decodedJwtToken->getUser();
return $user;
} else {
return null;
}
}
}
And it is declared as a service:
get.token.user.service:
class: UserBundle\Domain\Service\UserService
arguments: [ '#security.token_storage' ]
But all I get from $this->tokenStorage->getToken() is a web token with "anon." user, so it is not a JWT and jwtManager can't decode it.
UserService.php on line 25:
Symfony\Component\Security\Core\Authentication\Token\AnonymousToken {#16 ▼
-secret: "RXVaVx3"
-user: "anon."
-roleNames: []
-authenticated: true
-attributes: []
}
I also tried to get the jwt from the cookie in the controller and send it to the service as an argument, but I get an error from decode that I'm passing a string and it expects a TokenInterface object, so it did not worked neither.
How can I get the user from the token in the service? is there a best practice to login in the web through api than get the user from the jwt and send it to the render?
Edit: add the code to use lexik jwt and to save token in cookie:
# /config/packages/lexik_jwt_authentication.yaml
lexik_jwt_authentication:
secret_key: '%env(resolve:JWT_SECRET_KEY)%'
public_key: '%env(resolve:JWT_PUBLIC_KEY)%'
pass_phrase: '%env(JWT_PASSPHRASE)%'
token_ttl: 3600
user_identity_field: email
token_extractors:
cookie:
enabled: true
name: BEARER
the security file code
# /config/packages/security.yaml
security:
encoders:
UserBundle\Domain\Entity\User:
algorithm: auto
providers:
app_user_provider:
entity:
class: UserBundle\Domain\Entity\User
property: email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login:
pattern: ^/api/login
stateless: true
anonymous: true
json_login:
provider: app_user_provider
check_path: /api/login_check
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
refresh:
pattern: ^/api/token/refresh
stateless: true
anonymous: true
register:
pattern: ^/api/register
stateless: true
anonymous: true
api:
pattern: ^/api
stateless: true
anonymous: true
provider: app_user_provider
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
main:
anonymous: true
lazy: true
provider: app_user_provider
access_control:
- { path: ^/api/user, roles: IS_AUTHENTICATED_ANONYMOUSLY, methods: [GET] }
- { path: ^/api/linkpage, roles: IS_AUTHENTICATED_ANONYMOUSLY, methods: [GET] }
- { path: ^/api/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api/token/refresh, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
Listener to save jwt in a cookie and avoid the token to be in the response:
use Lexik\Bundle\JWTAuthenticationBundle\Event\AuthenticationSuccessEvent;
use Symfony\Component\HttpFoundation\Cookie;
class AuthenticationSuccessListener
{
private bool $secure = false;
private int $tokenTtl;
public function __construct(int $tokenTtl)
{
$this->tokenTtl = $tokenTtl;
}
public function onAuthenticationSuccess( AuthenticationSuccessEvent $event)
{
$response = $event->getResponse();
$data = $event->getData();
$token = $data['token'];
unset($data['token']); // remove token from response. It works.
unset($data['refresh_token']); // remove token from refresh token, even though I still get this token in the response
$event->setData($data);
$response->headers->setCookie(
new Cookie(
'BEARER',
$token,
(new \DateTime())->add(new \DateInterval('PT'. $this->tokenTtl . 'S')),
'/',
null,
$this->secure
)
);
}
}
#services.yaml
app.listener.authenticationsuccesslistener:
class: UserBundle\Application\Listeners\AuthenticationSuccessListener
arguments: ['%lexik_jwt_authentication.token_ttl%']
tags:
- { name: kernel.event_listener, event: lexik_jwt_authentication.on_authentication_success, method: onAuthenticationSuccess }
I still coded 2 more listeners for the refresh token, but I don't think they are needed.
The rest of the authentication is the default authentication code from lexik jwt bundle.
In the BEARER cookie is stored the jwt with the correct format, something like this:
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpYXQiOjE1OTgzNTE0ODYsImV4cCI6MTU5ODM1NTA4Niwicm9sZXMiOlsiUk9MRV9BRE1JTiIsIlJPTEVfVVNFUiJdLCJlbWFpbCI6ImFkbWluQGVtYWlsLmNvbSJ9.p5WYCxEE-VSxp09Eo7CxXoxi6zy1ZcnLJiBe1YGsrk3iFm7T-6JAWbvyb9ZW_-1jtpYcWQlFOjOf7uET4wRHvlvygnPOeZck7tZM8TUlSqMXIllMeVARz8mEUvXVwhDWEk5T7Ibw9c3VgfvyiLUgSb_cmSyK3DwtgPCd9vOYarkag9XKxkxNI9M1OHGL61v1NoQHdkXloC72xdUUMcj5Y8yCJWZFdOp8-Xtfq8ZChAHzwCjXUhC3VnBqZcMT0tAvtilwTGDYDykppNKK1vbNoyOex47wQH_ILEFuX5Eh1p2xfbc0lWm3Ip21z3EQ2M_eOQgZvHR65T3b2dv9g5GPiFp3CNo8AuW8m6rXjWK6NZXJO8qYodxI5cUYYyFooCfVXXU8JXzGQfCZIdOPw-iBGzQEfFuLL50_sAOVcxjklAYCFZYRHwFKWmwl1BwJF4mAw4jnNIAdMmc66Z17ul2Jep9apOO90C1dZzGuVKxWqglc9GZo7-teHt0dMsg0ADrvaOKNJUwDBGJ4lZpWx6_stcl7DkCdc5k1kePGdLa7YXRO3umPwa_FVYVgnT_Z9x7RtfnGioa2TZJCIdbJnuj0L90vkgFBjHqFdVydDaaBu3Y0mKoQ2v3Sf1so4-uwJm8z1vQVZleMQgFibMiyyk3YyDidhPSxxyp4u-4xPNOSDNo
If I am not logged in and don't have jwt or I delete the BEARER cookie I can't access the protected APIs ({"code": 401, "message": "JWT Token not found"}), when I have the jwt assigned I can request APIs correctly.
The problem was on the security.yaml configuration, specifically in the firewalls.main section, where I had to add the jwt_token_authenticator as the guard. Finally, my security.yaml is:
security:
encoders:
UserBundle\Domain\Entity\User:
algorithm: auto
providers:
app_user_provider:
entity:
class: UserBundle\Domain\Entity\User
property: email
jwt:
lexik_jwt: ~
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login:
pattern: ^/api/login
stateless: true
anonymous: true
json_login:
provider: app_user_provider
check_path: /api/login_check
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
require_previous_session: false
refresh:
pattern: ^/api/token/refresh
stateless: true
anonymous: true
register:
pattern: ^/api/register
stateless: true
anonymous: true
api:
pattern: ^/api
stateless: true
anonymous: true
provider: jwt
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
main:
anonymous: true
lazy: true
provider: jwt
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
logout:
path: app_logout
target: /
access_control:
- { path: ^/api/login_check, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api/token/refresh, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/logout, roles: IS_AUTHENTICATED_FULLY }
- { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
Then I had some problems with the logout, as the logout didn't erase the jwt cookies and the logout kept me logged in. So I made a Listener to the LogoutEvent and made the listener delete the cookies.
use Symfony\Component\Security\Http\Event\LogoutEvent;
class LogoutListener
{
public function onSymfonyComponentSecurityHttpEventLogoutEvent(LogoutEvent $event)
{
$response = $event->getResponse();
$response->headers->clearCookie('BEARER');
$response->headers->clearCookie('REFRESH_TOKEN');
$event->setResponse($response);
}
}
and declared it as a service:
app.listener.logout:
class: UserBundle\Application\Listeners\LogoutListener
tags:
- name: 'kernel.event_listener'
event: 'Symfony\Component\Security\Http\Event\LogoutEvent'
dispatcher: security.event_dispatcher.main
And now the login is working on the web without having to decode the jwt with the service I was using and pass the user to the front. Though the service that decoded the jwt, now is working fine.
I've lost almost a week with this issue, but finally I've found a solution and it's working fine. So I'll post it here to save time if anybody has some similar issue.
Authenticated: No appears in the Symfony2 dev toolbar after a successful login.
In my success handler I can access $token->getRoles() and see the role objects assigned to the user so it appears to be serializing okay.
So I'm not sure why it's not authenticating.
Here is my security.yml:
security:
encoders:
FixedApp\Model\User:
algorithm: sha1
encode_as_base64: false
iterations: 1
role_hierarchy:
ROLE_ADMIN: [ROLE_USER, ROLE_LIMITED_ADMIN]
ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
administrators:
entity: { class: FixedApp\Model\User, property: username }
firewalls:
dev:
pattern: ^/(_(profiler|wdt|error)|css|images|js)/
security: false
login:
pattern: ^/$
security: false
secured_area:
pattern: ^/
form_login:
check_path: fixed_app_authentication_login
login_path: fixed_app_homepage
username_parameter: form[username]
password_parameter: form[password]
default_target_path: fixed_app_hub_homepage
always_use_default_target_path: true
success_handler: security.authentication.success_handler
logout:
path: fixed_app_authentication_logout
target: fixed_app_homepage
access_control:
- { path: ^/log-in$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: /users/edit, roles: ROLE_ADMIN }
It not authenticating is a problem, because when I go to /users/edit as an admin it says Access Denied. So I need to figure out what is going on here. Any ideas would be most appreciated.
I saw a number of other people online with this same problem but I've never seen a solution put anywhere before - so hopefully this helps someone.
In UserRole.php class I was missing this function:
/**
* #see RoleInterface
*/
public function getRole()
{
return $this->role;
}
And secondly, in User.php class I made it implement EquatableInterface:
use Symfony\Component\Security\Core\User\EquatableInterface;
use Symfony\Component\Security\Core\User\UserInterface;
...
class User implements AdvancedUserInterface, EquatableInterface, \Serializable
{
...
public function isEqualTo(UserInterface $user)
{
if ($this->getId() == $user->getId())
{
return true;
}
else
{
return false;
}
}
And then it started working. The Symfony toolbar button went green, it says Authenticated: Yes and it lists all the roles for that user.
I don't understand my problem. I just want :
/ redirected /home
/home is not secured but logged user is able to navigate into
the whole website.
Non authenticated user is only able to see the homepage
People can register an account to access the whole website
So it's my security.yml config :
security:
encoders:
Siriru\AntBundle\Entity\User: sha512
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
main:
entity: { class: Siriru\AntBundle\Entity\User, property: username }
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
root:
pattern: ^/$
security: false
home:
pattern: ^/home$
security: false
login:
pattern: ^/login$
security: false
register:
pattern: ^/account/
security: false
secured_area:
pattern: ^/
form_login:
check_path: /login_check
login_path: /login
username_parameter: username
password_parameter: password
logout:
path: /logout
target: /home
Registration is ok, login too. But after the redirection to the homepage, user is not authenticated (in the symfony profiler "You are not authenticated."). If I reach the secured area, i'm logged but not authenticated.
<?php
namespace Siriru\AntBundle\Controller;
use Siriru\AntBundle\Form\Model\Registration;
use Siriru\AntBundle\Form\Type\RegistrationType;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Security\Core\SecurityContext;
use Symfony\Component\HttpFoundation\Response;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use JMS\SecurityExtraBundle\Annotation\Secure;
class AccountController extends Controller
{
/**
* #Route("/login", name="login")
* #Template()
*/
public function loginAction()
{
if ($this->get('request')->attributes->has(SecurityContext::AUTHENTICATION_ERROR)) {
$error = $this->get('request')->attributes->get(SecurityContext::AUTHENTICATION_ERROR);
} else {
$error = $this->get('request')->getSession()->get(SecurityContext::AUTHENTICATION_ERROR);
}
return array(
'last_username' => $this->get('request')->getSession()->get(SecurityContext::LAST_USERNAME),
'error' => $error,
);
}
/**
* #Route("/login_check", name="login_check")
*/
public function securityCheckAction()
{
// The security layer will intercept this request
}
/**
* #Route("/logout", name="logout")
*/
public function logoutAction()
{
// The security layer will intercept this request
}
/**
* #Route("/account/register", name="account_register")
* #Template()
*/
public function registerAction()
{
$form = $this->createForm(new RegistrationType(), new Registration());
return array('form' => $form->createView());
}
/**
* #Route("/account/create", name="account_create")
* #Template()
*/
public function createAction()
{
$em = $this->getDoctrine()->getEntityManager();
$form = $this->createForm(new RegistrationType(), new Registration());
$form->bind($this->getRequest());
if ($form->isValid()) {
$registration = $form->getData();
$user = $registration->getUser();
$factory = $this->get('security.encoder_factory');
$encoder = $factory->getEncoder($user);
$password = $encoder->encodePassword($user->getPassword(), $user->getSalt());
$user->setPassword($password);
$em->persist($user);
$em->flush();
return $this->redirect($this->generateUrl('homepage'));
}
return $this->render('SiriruAntBundle:Account:register.html.twig', array('form' => $form->createView()));
}
}
I need some help =) Thank you.
Try to change your firewall configuration to catch all the urls, then set anonymous: ~ and use access_control to restrict all the urls to ROLE_USER.
The problem is that the security session is not shared by default between different firewalls.
Something like this should work:
security:
encoders:
Siriru\AntBundle\Entity\User: sha512
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
main:
entity: { class: Siriru\AntBundle\Entity\User, property: username }
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
pattern: ^/
anonymous: ~
form_login:
check_path: /login_check
login_path: /login
username_parameter: username
password_parameter: password
logout:
path: /logout
target: /home
access_control:
- { path: ^/$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/home$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/login$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, roles: ROLE_USER }
I try to authenticate user:
<?php
/**
* #Route("/testLogin", name="testLogin")
*/
public function testLoginAction()
{
$em = $this->getDoctrine()->getEntityManager();
$user = $em->getRepository('ApplicationDefaultBundle:User')->findOneBy(array('id' => 126));
$providerKey = 'main';
$token = new UsernamePasswordToken($user, null, $providerKey, $user->getRoles());
$this->container->get('security.context')->setToken($token);
return $this->redirect($this->generateUrl('testCheck'));
}
/**
* #Route("/testCheck", name="testCheck")
*/
public function testCheckAction()
{
if (false === $this->get('security.context')->isGranted(
'IS_AUTHENTICATED_REMEMBERED'
)) {
return new Response('Not logged');
}
$user = $this->container->get('security.context')->getToken()->getUser();
return new Response($user->getUsername.' is logged');
}
But I get permanent 302 redirect to /login page.
security:
encoders:
Application\Bundle\DefaultBundle\Entity\User:
algorithm: sha512
iterations: 24
encode_as_base64: true
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SPECIALIST: ROLE_USER
ROLE_EMPLOYER: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
main:
entity: { class: Application\Bundle\DefaultBundle\Entity\User, property: username }
firewalls:
secured_area:
remember_me:
key: MySecretKeyBlablabla
lifetime: 36000000
path: /
domain: ~
pattern: ^/
form_login:
check_path: /login_check
login_path: /login
provider: main
logout:
path: /logout
target: /
anonymous: true
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
Code for authenticate I take from https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/Controller/RegistrationController.php
Error in app/logs/dev.log:
redirecting to authentication entry point (No Authentication Provider found for token of class "Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken".) [] []
I can't access to site until I clean cookies.
Try code from this answer. In your case firewall name is secured_area:
// your controller action
public function myAction()
{
// Authenticating user
$token = new UsernamePasswordToken($user, null, 'secured_area', $user->getRoles());
$this->get('security.token_storage')->setToken($token);
//For Symfony <= 2.3
//$this->get('security.context')->setToken($token);
$this->get('session')->set('_security_secured_area', serialize($token));
}
Verify that you have configured encoders section in security.yml, as configuration there has changed not very long time ago and it affects your problem.