Reputation: 31
I think I reached some limit with the Symfony security component. Here's my problem: I have two firewall to manage two users type (with two distinct entities) authentication and access to two different part of the website. I have a third part to manage files, uploads, ... that have to be private and both users types need to access it.
So I made multiple providers in security.yml:
providers:
# used to reload user from session & other features (e.g. switch_user)
core_user_provider:
entity:
class: Akyos\CoreBundle\Entity\User
property: email
platform_user_provider:
entity:
class: App\Entity\Platform\UserPlatform
property: email
file_manager_provider:
chain:
providers: [core_user_provider, platform_user_provider]
And multiple firewalls
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
core:
pattern: ^/(app|admin)/
context: shared
provider: core_user_provider
anonymous: lazy
guard:
authenticators:
- Akyos\CoreBundle\Security\CoreBundleAuthenticator
logout:
path: app_logout
target: 'home'
remember_me:
secret: '%kernel.secret%'
lifetime: 604800 # 1 week in seconds
path: /
file_manager:
pattern: ^/(file-manager)
context: shared
provider: file_manager_provider
anonymous: lazy
guard:
authenticators:
- App\Security\FileManagerAuthenticator
logout:
path: file_manager_logout
target: 'home'
remember_me:
secret: '%kernel.secret%'
lifetime: 604800 # 1 week in seconds
path: /
platform:
pattern: ^/(platorm_login|plateforme)
context: shared
provider: platform_user_provider
anonymous: lazy
guard:
authenticators:
- App\Security\PlatformAuthenticator
logout:
path: platform_logout
target: 'home'
remember_me:
secret: '%kernel.secret%'
lifetime: 604800 # 1 week in seconds
path: /
main:
anonymous: lazy
So a Platform user can't access Core, and a Core user can't access Platform. But both users needs to access File-manager, without re-log in. I can't place /file-manager urls under Core or Platform firewall because the other wouldn't grant access to it. So I need a third firewall to manage File-manager access. It use a chain provider that groups both Core and Platform users. It doesn't work either because if a Core user authenticate through the Core firewall it is not authenticated for the File-manager one, so it redirect to File-manager login page.. if the user logs in File-manager part it can access it, but when it turn back to Core part it has to re-connect again.
I tried several things but the closest solution is to use the context option on firewalls, so when a user is logged in through Core part it can access File-manager part without re-log because both firewalls shared the same context. That's what I want. But I also need it for the Platform firewall! So I also add same context option to it, and it works, both users types can access File-manager without log in again :D But as the three firewalls share the same context, Core users can access to Platform and vice-versa, and that breaks all the separation logic.. :'(
I need a way to tell security component "File-manager firewall has same context as Core firewall, and File-manager firewall has same context as Platform firewall, but Core and Platform firewalls doesn't share the same context". Something like this:
firewalls:
core:
context: core
file_manager:
context: [core,platform]
platform:
context: platform
main:
anonymous: lazy
I found nothing about it. Maybe it can't be done, maybe I have to create custom provider or authenticator to hack it. Maybe I can make it without Symfony, it's only php after all, so could I make the file-manager part accessible to every one (so under the main firewall) and add a Listener that would check if the request is for file-manager, find in session if there is a previous logged-in user, check if the user is a Core or a Platform user and then redirect if not... ? How can I find the previous Core or Platform user in session, when on a "main firewall" page (= authenticated as anonymous), without Symfony functions ? I'm not good enough to know how I could achieve that. Help ?
Upvotes: 1
Views: 1304
Reputation: 31
I've finally let 3 providers and firewalls with context shared between it. To prevent Core users to access Platform, and vice-versa, I added access_control:
- { path: ^/file-manager, roles: [ROLE_PLATFORM, ROLE_CORE] }
- { path: ^/core, roles: ROLE_CORE }
- { path: ^/plateforme, roles: ROLE_PLATFORM }
so it ends with a 403 access denied error. That's not the behavior I want so I also added 'access_denied_url' option on both core and platform firewall to redirect user on the good login page. As contexts are shared, users are already logged, so on login template I check instance of user object to advice him to disconnect first before trying to access this part.
{% if instanceOf(app.user, 'App\\Entity\\PlatformUser') %}
You're already logged in Platform space, please <a href="{{ path('platform_logout') }}">log out</a> before access Core space.
{% else %}
You're already logged in as {{ app.user.username }}, <a href="{{ path('core_logout') }}">log out</a> or <a href="{{ path('core_index') }}">access core panel</a>.
{% endif %}
It's a bit confusing to have context shared between parts that shouldn't share anything but access to file-manager, but no user can access other part so.. that works.
Upvotes: 2