Fos userBundle logout issue - php

Following are my security.yml settings
form_login:
check_path: /%cluburlidentifier%/backend/login_check
login_path: /%cluburlidentifier%/backend/signin
logout:
path: /%cluburlidentifier%/backend/signout
target: /%cluburlidentifier%/backend/signin
I signin using /myclub/backend/signin. Permission of the user is Superadmin. When i tried to logout using different path, like, /myhome/backend/signout, it shows error "You must activate the logout in your security firewall configuration.".
%cluburlidentifier% is a dynamic parameter taken from url.
How can I change the logout path defined in the security.yml after login..? Is there any session or something like to set...??
Please help me !!
The following is my full security.yml firewall config
firewalls:
frontend:
pattern: /%cluburlidentifier%/backend/.*
provider: fos_userbundle
anonymous: ~
form_login:
check_path: /%cluburlidentifier%/backend/login_check
login_path: /%cluburlidentifier%/backend/signin
username_parameter: _username
password_parameter: _password
csrf_parameter: _csrf_token
intention: authenticate
post_only: true
remember_me: true
#use_referer: true
always_use_default_target_path: true
default_target_path: contact_index
logout:
path: /%cluburlidentifier%/backend/signout
target: /%cluburlidentifier%/backend/signin
invalidate_session: true
delete_cookies:
a: { path: null, domain: null }
b: { path: null, domain: null }
remember_me:
key: "123456"
lifetime: 31536000 # 365 days in seconds
path: fos_user_security_login
domain: ~ # Defaults to the current domain from $_SERVER
always_remember_me: true
In that, first im trying to login with url like "localhost:8080/twilight/backend/signin", where twilight is the cluburl identifier. Afet login he redirects to "localhost:8080/twilight/backend/contact"
The logged user have the superadmin previlage. So he can moved to the next club by changing the cluburl identifier without triggering one more login. That means, just changing the url to "localhost:8080/myclub/backend/contact" in the browser..
That also works...But the problem is, when he tried to logout using the url "**localhost:8080/myclub/backend/logout" after login with "localhost:8080/twilight/backend/signin", couldn't work...
I know it is a negative requirement...But is it possible...??**
Also i didn't get the logged user details if i changed the url path...Is there any way to that also?
Plz help me....

Related

Symfony 5.4 security multiple firewalls

I'm trying to split the authentication of a user from the authentication of an admin.
So I created 2 firewalls and 2 different access controls.
My security.yaml looks like that:
enable_authenticator_manager: true
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
providers:
owner_authentication:
entity:
class: App\Entity\Merchant\Owner
property: emailAddress
user_authentication:
entity:
class: App\Entity\User\User
property: emailAddress
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
user:
lazy: true
pattern: ^/admin/login/
provider: user_authentication
user_checker: App\Security\AuthentificableModelChecker
form_login:
provider: user_authentication
default_target_path: app.dashboard.index
use_referer: true
use_forward: false
login_path: app.authorization.admin_login
check_path: app.authorization.admin_login
username_parameter: login[emailAddress]
password_parameter: login[password]
logout:
path: app.authorization.logout
target: app.authorization.admin_login
main:
lazy: true
pattern: ^/
provider: owner_authentication
user_checker: App\Security\AuthentificableModelChecker
form_login:
provider: owner_authentication
default_target_path: app.dashboard.index
use_referer: true
use_forward: false
login_path: app.authorization.login
check_path: app.authorization.login
username_parameter: login[emailAddress]
password_parameter: login[password]
logout:
path: app.authorization.logout
target: app.authorization.login
access_control:
- { path: ^/admin/login, roles: PUBLIC_ACCESS}
- { path: ^/login, roles: PUBLIC_ACCESS }
- { path: ^/, roles: ROLE_USER }
Everything works fine on the main firewall, but when I submit the button using user (admin) firewall, the login page refreshes itself and nothing happens. I don't have any error.
** If I add user(admin) login on the main firewall, then /admin/login will work fine and the other one won't work anymore.
When I call $authenticationUtils->getLastAuthenticationError() I don't get any error. But the validations don't work either.
This is how my Controller looks like:
public function adminLogin(AuthenticationUtils $authenticationUtils): Response
{
if ($this->getUser()) {
return $this->redirectToRoute('app.dashboard.index');
}
$loginForm = $this->createForm(LoginType::class, ['emailAddress' => $authenticationUtils->getLastUsername()]);
return $this->renderForm('app/pages/authorization/admin_login.html.twig', [
'title' => 'Log in',
'login_form' => $loginForm,
'error' => $authenticationUtils->getLastAuthenticationError()?->getMessageKey(),
]);
}
It's the same problem this guy had: https://grafikart.fr/forum/35234 but I can't find any solution for this.
Finally, I found the answer so I'll post it here: https://stackoverflow.com/a/42352112/8003007
What I had to do was to add a context: my_context in both firewalls.
It was a difficult option to identify because it doesn't appear in the official and current Symfony documentation but only in the previous ones, like Symfony 3.4.

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()});

symfony Delete remember me cookie when logging out

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

Symfony2 auto-login after user registration

I have seen some posts in this regard, specifically Auto-Login via URL with symfony2 (which I can't use because I do not know what needs to go into $request) and Automatic post-registration user authentication. I tried the latter, but it is not logging in.
Code from security.yml
firewalls:
admin_login_firewall:
pattern: ^/admin/login$
anonymous: ~
admin:
pattern: ^/admin
form_login:
login_path: admin_login
check_path: admin_login_check
default_target_path: admin_dashboard
logout:
path: admin_logout
target: admin_login
http_basic:
realm: "Licensing Admin Portal"
member_login_firewall:
pattern: ^/members/login$
anonymous: ~
members:
pattern: ^/members
form_login:
login_path: member_login
check_path: member_login_check
default_target_path: member_dashboard
logout:
path: member_logout
target: home
http_basic:
realm: "Licensing Member Portal"
encoders:
Pmb\LicensingBundle\Entity\User: plaintext
access_control:
- { path: ^/admin/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/members/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin, roles: ROLE_ADMIN }
- { path: ^/members/, roles: ROLE_USER }
Code snippet from Controller function saveUserAction():
... // Code preceding this point creates user entity and sets all fields
$em = $this->getDoctrine()->getManager();
if (empty($data['user_id'])) $em->persist($user);
$em->flush();
if (!empty($organization)) $this->linkOrganizationUserAction($organization,$user, true);
if (isset($data['registering']))
{
$token = new UsernamePasswordToken($user, null, 'members', $user->getRoles());
$this->get('security.context')->setToken($token);
$this->get('session')->set('_security_main',serialize($token));
}
return $this->createJsonResponse($user);
I am trying to log in to the members firewall. I do not know enough about this to troubleshoot. Most of this is just copy/paste/edit. Any help / explanation would be greatly appreciated. I also read the article under Symfony2 auto-login after registration, but I do not see the significance of this, as I do not need have users logged in accross different firewalls, and just need the user logged in under the members firewall.
One thing that I DID notice, is that the user entity is having its salt field populated when persiting to the database, even though I did not set a salt and I cannot see anything auto-setting the salt. I am not yet using the salt as I am not yet encrypting my passwords (just trying to get it working with plain text passwords first), and when trying to log in with a created user (which does get created, just not getting logged in) I cannot log in unless I clear the salt on the user. I don't know if this has anything to do with the fact that the auto-login is not working.
The issue here was with the line $this->get('session')->set('_security_main',serialize($token));. The "_main" of "security_main" is also the firewall that you are authenticating against. So it should have been "_security_members". After changing it the code worked as is.

Symfony2 - FOSUserBundle - Multiple Login Locations

I'm using the FOSUserBundle and I require the ability to login from 2 different routes(or more). These routes will have different templates and also login to different areas. The only thing that differs between the logins is the permission required.
The routes will be something along the lines of
site.com/login
site.com/admin/login
and also possible site.com/ajax_login
I've been able to work out how to get different templates to render by ripping out everything but the CSRF token from the FOSUserBundle login.html.twig(that is overriden) then creating routes that render their own login boxes and also the login route(so that just the CSRF token gets rendered).
This doesnt work for admin/login as the form posts back to login and if it fails it displays that page instead.
Is there any easy way to achieve this?
I was stucked with the same question for a while and then i created a solution on my own. I knew there must be an easy solution...
I've submitted pull request which allows you to create new login templates more easily. Check the pull request here: https://github.com/FriendsOfSymfony/FOSUserBundle/pull/1186.
There is also another quite easy way how to achieve this. Extend SecurityController and change renderLogin method with following content
protected function renderLogin(array $data, $template)
{
return $this->container->get('templating')->renderResponse('YourBundle:Security:login.html.twig');
}
Then create a route to your newly created controller:
admin.login:
pattern: /admin/login
defaults: { _controller: YourBundle:Security:login }
After this only you have to do is to alter your security config accordingly. Change your form_login login_path to /admin/login and you are good to go.
Here's what I eventually came up with, basically the both use the same firewall and share the same context so when I login via the normal login they also get access to the admin(assuming they are admin)
firewalls:
admin:
context: site
switch_user: true
pattern: /admin(.*)
form_login:
provider: fos_userbundle
login_path: /admin/login
success_handler: admin_authentication_handler
use_forward: false
check_path: /admin/login_check
failure_path: null
use_referer: true
always_use_default_target_path: true
default_target_path: /admin/
logout:
path: /admin/logout
target: /admin/login
anonymous: true
public:
pattern: ^/
context: site
form_login:
login_path: /login
success_handler: authentication_handler
failure_handler: authentication_handler
provider: fos_userbundle
anonymous: true
logout: true
Of course if you need to make an AJAX login box you need to override the success and failure handlers and check to see if the request is a XmlHttpRequest and return the result of the login.
Could you post your template?
Have you edited the path correctly in the template?
<form action="{{ path('form_submit') }}" method="post" {{ form_enctype(form) }}>
You want to send the form to the correct controller.

Categories