symfony Delete remember me cookie when logging out - php

There is a delete_cookies in the security configuration file: http://symfony.com/doc/current/reference/configuration/security.html
I have remember_me enabled. Everything works fine except when an user goes to the 'logout' link (directly from the url bar), I want symfony to delete the REMEMBERME cookie. How can I achieve that? Am I missing something?
When I go to url /app/logout, I can see the chrome dev tools that I still have the REMEMBERME cookie.
This is my security.yml file:
firewalls:
app_secured:
anonymous: ~
switch_user: true
pattern: ^(/$|/login$|/app/)
form_login:
login_path: login
check_path: login_check
csrf_provider: form.csrf_provider
default_target_path: index
always_use_default_target_path: true
remember_me:
key: "%secret%"
lifetime: 2592000
path: ~
domain: ~
logout:
invalidate_session: true
delete_cookies:
REMEMBERME: { path: null, domain: null}
path: logout
target: login
access_control:
- { path: ^/app/_sys/, roles: ROLE_NO_ACCESS }
- { path: ^/app/, roles: ROLE_USER }
- { path: ^/app/admin/, roles: ROLE_ADMIN }
Routing.yml
login:
path: /
defaults: { _controller: AppWebBundle:Login:login }
login_check:
path: /login_check
logout:
path: /app/logout
LoginController.php
/**
* Login controller.
* #Route("/")
*/
class LoginController extends Controller
{
/**
* Login page
* #Route("/login", name="login2")
*/
public function loginAction(Request $request){
/** Reduced for simplicity, same code as:
http://symfony.com/doc/current/book/security.html#using-a-traditional-login-form **/
return $this->render('AppWebBundle:Default:login.html.twig', ['last_username' => $lastUsername,'error'=> $error,]);
}
}

$response = new Response();
$response->headers->clearCookie('REMEMBERME');
$response->send();
You could delete the cookie with this in a controller

I found out that it doesn't work if you put directly the logout url into the url bar. The user has to click logout in order to work.
Creating a link Logout and clicking it worked.

Removing in server side the REMEMBERME token after logout should be automatic but it's not.
To do so, you'll have to change the way you store your token.
Since Symfony 2.8, the easy way is to use Doctrine to store tokens in database:
# config/packages/security.yaml
security:
# ...
firewalls:
main:
# ...
remember_me:
secret: '%kernel.secret%'
# ...
token_provider:
doctrine: true
Doing this will not only store token in database, it will invalidate it on logout event.
You can learn more in the documentation : https://symfony.com/doc/6.1/security/remember_me.html

Related

Symfony: Redirect to user profile after login with id

In my application I wish to redirect users to profile after login, so I'm using an hidden input with name _target_path and value /profile/{userid} in my TWIG page (I've tried to make an IF statement to check when the app.user.username variable exist, but this isn't the right logic)
<input type="hidden" name="_target_path" value="/profile/{% if app.user.username is defined %}{{ app.user.username }}{% endif %}" />
This isn't working as expected cause naturally when I render the form I've not already set the username in session.
Here is my loginAction() in AuthController.php
/**
* #Route("login/", name="login")
*/
public function loginAction(Request $request)
{
$authenticationUtils = $this->get('security.authentication_utils');
$error = $authenticationUtils->getLastAuthenticationError();
$lastUsername = $authenticationUtils->getLastUsername();
return $this->render('auth/login.html.twig', array(
'last_username' => $lastUsername,
'error' => $error,
));
}
I can reach the profile page using the parameter ID, so the url is like example.com/profile/1 without the ID it's causing a 404.
So I need to redirect the user after login to profile/{id} taking it from autenticationUtils
I'm really sure that my logic is incorrect, but I can't find nothing in the web that can solve my issue.
Here is my security.yml
security:
providers:
user_db:
entity: { class: AppBundle\Entity\User, property: username }
encoders:
Symfony\Component\Security\Core\User\User:
algorithm: bcrypt
cost: 12
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: ~
form_login:
login_path: login
check_path: login
logout: true
logout:
csrf_parameter: _csrf_token
csrf_token_generator: ~
csrf_token_id: logout
path: /logout
target: /
success_handler: ~
invalidate_session: true
delete_cookies:
name:
path: null
domain: null
handlers: []
admin:
pattern: ^/
provider: user_db
http_basic:
realm: 'Admin Area'
provider: in_memory
form_login: ~
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin, roles: ROLE_ADMIN }
- { path: ^/profilo, roles: [ROLE_USER, ROLE_ADMIN] }
What you need is changing the DefaultAuthenticationSuccessHandler (given you use the plain symfony mechanism wihtout any bundles like FOSUserBundle involved).
First thing make your own Handler (or parts, here especially onAuthenticationSuccess):
namespace ...
use ...
class AuthenticationSuccessHandler extends DefaultAuthenticationSuccessHandler
{
/**
* {#inheritdoc}
*/
public function onAuthenticationSuccess(Request $request, TokenInterface $token)
{
**DO your logic here**
//or call parent if you want default behaviour
return parent::onAuthenticationSuccess($request, $token);
}
}
Inject more services as needed.
Second overwrite the default service in your DI:
security.authentication.success_handler:
class: AppBundle\Handler\AuthenticationSuccessHandler
arguments: ['#security.http_utils', {}]
tags:
- { name: 'monolog.logger', channel: 'security' }
From the Symfony documentation: Changing the default Page
Changing the default Page:
First, the default page can be set (i.e. the page the user is redirected to if no previous page was stored in the session). To set it to the default_security_target route use the following config:
# app/config/security.yml
security:
# ...
firewalls:
main:
form_login:
# ...
default_target_path: default_security_target
Now, when no URL is set in the session, users will be sent to the default_security_target route.
You can make it so that users are always redirected to the default page regardless of what URL they had requested previously by setting the always_use_default_target_path option to true:
# app/config/security.yml
security:
# ...
firewalls:
main:
form_login:
# ...
always_use_default_target_path: true
You should do something like this in PHP after login :
return $this->redirectToRoute('name_profile_route', { id : $this->getUser()->getId()});

Symfony3 Keeping locale after login

Problem I have, is when user changes language in login page - it works, but after user login - it is back to default again. How to make it possible to the keep same language user selected before login, to stay after login?
I've tried looking this up on stackoverflow, but wasn't able to find any working result.
security.yml:
security:
encoders:
AppBundle\Entity\User:
algorithm: bcrypt
role_hierarchy:
ROLE_ADMIN: ROLE_PREMIUM
ROLE_PREMIUM: ROLE_USER
providers:
our_db_provider:
entity:
class: AppBundle:User
property: email
in_memory:
memory: ~
firewalls:
# disables authentication for assets and the profiler, adapt it according to your needs
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: ~
form_login:
#galima nurodyti kur nukreipia loginas
login_path: login
check_path: login
csrf_token_generator: security.csrf.token_manager
logout:
path: /logout
pattern: ^/
http_basic: ~
provider: our_db_provider
access_denied_url: homepage
routing.yml
app:
resource: "#AppBundle/Controller/"
type: annotation
prefix: /{_locale}
requirements:
_locale: lt|en|ru
root:
path: /
defaults:
_controller: FrameworkBundle:Redirect:urlRedirect
path: /%locale%/
permanent: true
login:
path: /{_locale}/login
defaults: { _controller: AppBundle:Security:login }
requirements:
_method: GET
_locale: lt|en|ru
logout:
path: /logout
defaults:
_controller: FrameworkBundle:Redirect:urlRedirect
path: /{_locale}/login
permanent: true
register:
path: /{_locale}/register
defaults: { _controller: AppBundle:Registration:register }
requirements:
_method: GET
_locale: lt|en|ru
Language changed by:
<ul class="top-menu-list top-menu-languages">
<li>LT</li>
<li>EN</li>
<li>RU</li>
</ul>
Any ideas or examples would be appreciated!
By default, the Security component retains the information of the last request URI (e.g. /en/admin) in a session variable named _security.main.target_path (with main being the name of the firewall, defined in security.yml). Upon a successful login, the user is redirected to this path, as to help them continue from the last known page they visited.
Note: No matter how many times the language is changed on the login page, because the firewall always redirect to /en/admin/ after success login, so the locale changes again to en.
To fix that you might need to change the default Target Path Behavior:
The Exception Listener Class:
// src/AppBundle/Security/Firewall/ExceptionListener.php
use Symfony\Component\Security\Http\Firewall\ExceptionListener as BaseExceptionListener;
class ExceptionListener extends BaseExceptionListener
{
use TargetPathTrait;
protected function setTargetPath(Request $request)
{
if ($request->hasSession() && $request->isMethodSafe(false) && !$request->isXmlHttpRequest()) {
$this->saveTargetPath(
$request->getSession(),
// the firewall name
'admin',
// save the route name instead of the URI
$request->attributes->get('_route')
);
}
}
}
This generate the old route after login with the current locale.
Configuration:
For Symfony 2:
# app/config/services.yml
parameters:
# ...
security.exception_listener.class: AppBundle\Security\Firewall\ExceptionListener
For Symfony 3:
You might need create a compiler pass and change this class manually:
// src/AppBundle/DependencyInjection/Compiler/ExceptionListenerPass.php;
class ExceptionListenerPass implements CompilerPassInterface
{
/**
* {#inheritdoc}
*/
public function process(ContainerBuilder $container)
{
$definition = $container->getDefinition('security.exception_listener.admin');
$definition->setClass('AppBundle\Security\Firewall\ExceptionListener');
}
}
Finally register the compiler pass in your bundle:
// src/AppBundle/AppBundle.php
class AppBundle extends Bundle
{
public function build(ContainerBuilder $container)
{
$container->addCompilerPass(new ExceptionListenerPass());
}
}

Redirect anonymous user to /login page

So, I'm using FOSUserBundle and symfony 2.8 project
if there is any way to redirect anonymous user to /login page, if he required / page?
Use a firewall to protect /:
# app/config/security.yml
security:
firewalls:
app:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_token_generator: security.csrf.token_manager
logout: true
anonymous: true
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, role: ROLE_ADMIN }
More details in the FOSUserBundle docs.
First, check if the user is authorized. Then, use an if condition to redirect the user.
Full example of your index:
public function indexAction()
{
$context = $this->container->get('security.authorization_checker');
if (!($context->isGranted('IS_AUTHENTICATED_REMEMBERED'))) {
$this->redirect('http://yourpage.com/login');
} else {
//Do your other stuff here
}
}

Restrict or redirect logged in users from login page

I am using Symfony 2.7, installed FOSuserbundle, everything is working fine. My users are being created and I can login with them, but logged in users can enter the log in page, which doesn't seem logic to me. I've looked a bit for answers and found out I have to configure my security.yml file, but it still doesn't work, anyone can enter the login page.
I found that I have to set
- { path: ^/, role: ROLE_USER}
but that gives me a redirect loop.
Here is what I have in it
firewalls:
# disables authentication for assets and the profiler, adapt it according to your needs
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_provider: security.csrf.token_manager # Use form.csrf_provider instead for Symfony <2.4
logout: true
anonymous: true
# activate different ways to authenticate
# http_basic: ~
# http://symfony.com/doc/current/book/security.html#a-configuring-how-your-users-will-authenticate
# form_login: ~
# http://symfony.com/doc/current/cookbook/security/form_login_setup.html
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/profile, role: ROLE_USER }
- { path: ^/admin/, role: ROLE_ADMIN }
Override the loginAction of tge SecurityController, this way:
class SecurityController extends BaseSecurityController
{
public function loginAction(Request $request)
{
if( $this->container->get('security.context')->isGranted('IS_AUTHENTICATED_FULLY') {
return $this->redirect($this->generateUrl('any_route_you_want'))
}
return parent::loginAction($request);
}
}
Edit : To learn how to override any part of a Bundle, this would be helpful
Allready tryed this Solution ?
FOSUserBundle redirect from login page after logged in
PHP:
You can override FOSUserBundle\Controller\SecurityController and add the following code at the top of loginAction.
use Symfony\Component\HttpFoundation\RedirectResponse;
// ...
public function loginAction(Request $request)
{
$securityContext = $this->container->get('security.context');
$router = $this->container->get('router');
if ($securityContext->isGranted('ROLE_ADMIN')) {
return new RedirectResponse($router->generate('admin_home'), 307);
}
if ($securityContext->isGranted('ROLE_USER')) {
return new RedirectResponse($router->generate('user_home'), 307);
}
// ...
yaml:
The easier solution is to add these two lines to your app/config/security.yml:
always_use_default_target_path & default_target_path, e.g.:
firewalls:
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_provider: form.csrf_provider
login_path: /login
check_path: /login_check
always_use_default_target_path: false
default_target_path: /your/start/path/

Symfony2 Logout code placement, where do I put the invalidate code

New Symfony user here...
The examples in the Symfony Documentation don't actually have any examples of how to do a proper logout. Here is my security.yml
security:
encoders:
Symfony\Component\Security\Core\User\User: plaintext
AppBundle\Entity\User: bcrypt
role_hierarchy:
ROLE_ADMIN: [ROLE_USER]
providers:
chain_provider:
chain:
providers: [in_memory, user_db]
in_memory:
memory:
users:
admin: { password: adminpass, roles: ROLE_ADMIN }
user_db:
entity: { class: AppBundle:User, property: username }
firewalls:
main:
pattern: /.*
form_login:
login_path: /login
check_path: /login_check
default_target_path: /
logout:
path: /logout
target: /
invalidate_session: true
delete_cookies:
name:
path: null
domain: null
security: true
anonymous: true
access_control:
- { path: /login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: /cms/user, roles: ROLE_ADMIN }
- { path: /.*, roles: IS_AUTHENTICATED_ANONYMOUSLY }
I was under the impression with those settings that simply hitting the /logout route the session would be destroyed and the user would be redirected to the login page. However in trying to do this, I get a no route found error.
I found this code here on stack-overflow...
$this->get('security.token_storage')->setToken(null);
$this->get('request')->getSession()->invalidate();
Great, but I'm so new in Symfony that I don't know where to put it. All of the examples here on Stack give that code, but don't say how to implement it. Do I write a logout action like this?
/**
* #Route("/logout")
*/
public function logoutAction() {
$this->get('security.token_storage')->setToken(null);
$this->get('request')->getSession()->invalidate();
//if this works how do I redirect to another route,
//specifically back to /login
return $this->render(
//do i need a template?
//do i need the array here?
);
}
No needed to write logout action in controller. All you have to do, is add the route with logout path.
In app/config/routing.yml:
user_logout:
path: /logout

Categories