I'm working in a Symfony 2.8.x app and I need to setup two secured areas: chat
and admin
. This means that chat
and admin
will use the same login template (if this is possible and I don't need to setup different one for this purpose). I have googled before ask here and there is a few things related showing up and I read a lot of post about this topic: 1, 2, 3, 4 just as an example of them but I am doing something wrong since I can't get this working properly. This is how /app/config/security.yml
looks like (just the firewalls and access_control piece of code):
security:
....
firewalls:
admin:
pattern: /admin/(.*)
anonymous: ~
form_login:
provider: fos_userbundle
csrf_provider: security.csrf.token_manager
login_path: fos_user_security_login
check_path: fos_user_security_check
use_forward: true
always_use_default_target_path: true
default_target_path: /admin
target_path_parameter: _target_path
use_referer: true
remember_me: true
logout:
target: /admin
remember_me:
secret: '%secret%'
lifetime: 604800 # 1 week in seconds
path: /
chat:
pattern: ^/chat/(.*)
anonymous: ~
form_login:
provider: fos_userbundle
csrf_provider: security.csrf.token_manager
login_path: fos_user_security_login
check_path: fos_user_security_check
use_forward: true
always_use_default_target_path: true
default_target_path: /chat
target_path_parameter: _target_path
use_referer: true
remember_me: true
logout: ~
remember_me:
secret: '%secret%'
lifetime: 604800 # 1 week in seconds
path: /
access_control:
- { path: ^/admin/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/resetting$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/logout$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/chat/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/chat/resetting$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/chat/logout$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/chat/, role: ROLE_CHATTER }
- { path: ^/admin/, role: ROLE_ADMIN }
Now this is the config for my bundles at app/config/routing.yml
:
platform_chat:
resource: "@PlatformChatBundle/Controller/"
type: annotation
prefix: /chat/
options:
expose: true
platform_admin:
resource: "@PlatformAdminBundle/Controller/"
type: annotation
prefix: /admin/
options:
expose: true
And for FOSUserBundle
I have tried this two (both without success and each at a time):
#FOSUser
fos_user:
resource: "@FOSUserBundle/Resources/config/routing/all.xml"
#FOSUser
# this second causes doubts to me since I think I will need
# to repeat the same routes for chat prefix but I'm not sure at all
fos_user_security:
resource: "@FOSUserBundle/Resources/config/routing/security.xml"
prefix: /admin
fos_user_profile:
resource: "@FOSUserBundle/Resources/config/routing/profile.xml"
prefix: /admin/profile
fos_user_register:
resource: "@FOSUserBundle/Resources/config/routing/registration.xml"
prefix: /admin/register
fos_user_resetting:
resource: "@FOSUserBundle/Resources/config/routing/resetting.xml"
prefix: /admin/resetting
fos_user_change_password:
resource: "@FOSUserBundle/Resources/config/routing/change_password.xml"
prefix: /admin/profile
I have overwrite the login template at app/Resources/FOSUserBundle/views/Security/login.html.twig
. (if source is needed I can provide just ommit for not make the post longer than it's already).
When I call the URL: http://domain.tld/app_dev.php/admin
and try to login I got this error:
Translation not found. Context: { "id": "Symfony\Component\Security\Core\Exception\BadCredentialsException: Bad credentials. in /var/www/html/platform-cm/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Authentication/Provider/UserAuthenticationProvider.php:90\nStack trace:\n#0
(I can provide the full stacktrace if needed)
this is weird to me but perhaps it's caused for a bad configuration since I have double checked credentials.
When I call the URL: http://domain.tld/app_dev.php/chat
and try to login I got Access Denied
but it's right because I am redirected to http://domain.tld/app_dev.php/admin/
. Can any give me some help on this configuration? I am stuck and can't move forward because of this
2nd approach
This is a second approach bassed on @heah suggestion using a listener but is not working too I am still getting the same "Bad credentials" message and can't login at all. I have changed back the routing.yml
to this:
#FOSUser
fos_user:
resource: "@FOSUserBundle/Resources/config/routing/all.xml"
I have changed back the security.yml
to this:
security: ... firewalls: admin: pattern: ^/ anonymous: ~ form_login: provider: fos_userbundle csrf_provider: security.csrf.token_manager login_path: fos_user_security_login check_path: fos_user_security_check
# if true, forward the user to the login form instead of redirecting
use_forward: true
# login success redirecting options (read further below)
always_use_default_target_path: true
default_target_path: /admin
target_path_parameter: _target_path
use_referer: true
remember_me: true
logout:
target: /admin
remember_me:
secret: '%secret%'
lifetime: 604800 # 1 week in seconds
path: /
access_control:
- { path: ^/admin/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/resetting$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/logout$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/chat/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/chat/resetting$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/chat/logout$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/chat/, role: ROLE_CHATTER }
- { path: ^/admin/, role: ROLE_ADMIN }
Then I have defined a listener for the event security.interactive_login
as suggested in app/config/config.yml
:
parameters:
account.security_listener.class: PlatformAdminBundle\Listener\SecurityListener
Then at app/config/services.yml
:
services:
account.security_listener:
class: %account.security_listener.class%
arguments: ['@security.context', '@session']
tags:
- { name: kernel.event_listener, event: security.interactive_login, method: onSecurityInteractiveLogin }
And finally here is the class definition at src/PlatformAdminBundle/Listener/SecurityListener.php
:
namespace PlatformAdminBundle\Listener;
use Symfony\Component\Security\Core\SecurityContextInterface;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
class SecurityListener
{
public function __construct(SecurityContextInterface $security, Session $session)
{
$this->security = $security;
$this->session = $session;
}
public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
{
$user = $this->security->getToken()->getUser();
var_export($user);
}
}
I am running the same issue, again, perhaps I am doing something wrong and I am not seeing but I accept any ideas. What could be wrong here?
3rd approach
I have take a review to my code and change it slighty mostly following @heah suggestions. So, now security.yml
is as follow:
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/logout$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/chat/, role: ROLE_CHATTER }
- { path: ^/admin/, role: ROLE_ADMIN }
the changes at services.yml
are basically fix the arguments since security.context
has been split in Symfony 2.6+ although I am not using it at all:
services:
...
account.security_listener:
class: %account.security_listener.class%
arguments: ['@security.authorization_checker']
tags:
- { name: kernel.event_listener, event: security.interactive_login, method: onSecurityInteractiveLogin }
And lastly the changes at the class PlatformAdminBundle/Listener/SecurityListener.php
:
namespace Clanmovil\PlatformAdminBundle\Listener;
use Symfony\Component\Finder\Exception\AccessDeniedException;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
class SecurityListener
{
public function __construct(AuthorizationCheckerInterface $authorizationChecker)
{
$this->security = $authorizationChecker;
}
public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
{
if ($this->security->isGranted('ROLE_ADMIN')) {
// this is something for testing
throw new AccessDeniedException(
'Access Denied. You are ADMIN'
);
} elseif ($this->security->isGranted('ROLE_CHATTER')) {
// this is something for testing
throw new AccessDeniedException(
'Access Denied. You are CHATTER'
);
}
}
}
When I login as user with ROLE_CHATTER
everything seems to work since I got the AccessDenied exception but when I try to login as a user with ROLE_ADMIN
it stop working and I come back to the initial error: Bad credentials
, why is this? I am getting crazy!!
prefix : /chat
routes.yml
config (without prefixes)fos_user
routes in the 2nd approach (no more admin prefix) as your pattern of the firewall. So you also need to change paths inaccess_control
as/admin/login
won't match but/login
will3rd
approach, still not working under admin users