Warm tip: This article is reproduced from serverfault.com, please click

Internationalized routing don't work fine with security access controls

发布于 2020-11-29 12:35:51

I'm trying to use Internationalized routing.

So for one route many URLs.

But one route still being uniquely identified by its name.

This is a great feature but the doc don't says how to deal with the security component.

In fact, I'm using url to make a basic secure of the app.

But since every URL can be different regarding on the locale, the only way I found to make thing still working is to duplicate as many path as route name got.

This my security.yaml right now :

# ./config/packages/security.yaml @ line 27 -- 41
access_control:
        # Allow every user to visit index_no_locale page (Default page when no locale is selected).
        # This will redirect to login page with default locale.
        - { path: ^/$, roles: IS_AUTHENTICATED_ANONYMOUSLY}
        # Allow anonymous to visit login page.
        - { path: ^(/en/login|/fr/connexion|/de/verbindung), roles: IS_AUTHENTICATED_ANONYMOUSLY}
        # Allow anonymous to visit password_reset page.
        - { path: ^(/en/password/reset|/fr/mot-de-passe/reinitialisation|/de/passwort/zurücksetzen), roles: IS_AUTHENTICATED_ANONYMOUSLY}
        # Allow anonymous to visit email_send_password_forgot
        - { path: ^(/en/email/send/password/forgot|/fr/courriel/envoyer/mot-de-passe|/de/email/schreiben/passwort/vergessen), roles: IS_AUTHENTICATED_ANONYMOUSLY}
        # Allow only admin to visit admin url
        - { path: ^/admin, roles: IS_ADMIN}
        # Allow authenticated user ONLY to visit every other urls
        # Specific user right controls are managed inside controller
        - { path: ^/, roles: IS_AUTHENTICATED_FULLY}

As I say this is working, but I've got to duplicate path for every existing route.

I let you see the route for better understand :

> php bin/console debug:router
  Name                             Method   Scheme   Host   Path      
-------------------------------- -------- -------- ------ --------------------
  password_reset.en                ANY      ANY      ANY    /{_locale}/password/reset/{user_id}/{token_value}           
  password_reset.fr                ANY      ANY      ANY    /{_locale}/mot-de-passe/reinitialisation/{user_id}/{token_value}
  password_reset.de                ANY      ANY      ANY    /{_locale}/passwort/zurücksetzen/{user_id}/{token_value}    
  login.en                         ANY      ANY      ANY    /{_locale}/login                                            
  login.fr                         ANY      ANY      ANY    /{_locale}/connexion                                        
  login.de                         ANY      ANY      ANY    /{_locale}/verbindung                                       
  logout                           ANY      ANY      ANY    /{_locale}/logout                                           
  index_no_locale                  ANY      ANY      ANY    /                 
...

I really don't like this for evident reason of redundant modifications to opeer each time a URL have to be added or modified.

The main problem is when user is not logged in and visit a URL where IS_AUTHENTICATED_FULLY role is required.

So now the 'Voter' say that access is denied and redirect response to login_path define into security.yaml

Here is the problem. I can't define a proper path to login_path because I can't guess what was the locale used by the user. So I hardcoded this :

# ./config/packages/security.yaml @ line 1 -- 21
security:
    # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
    providers:
        ...
    firewalls:
        dev:
            ...
        main:
            anonymous: true

            form_login:
                login_path: /en/login
                check_path: /en/login
                provider:   my_provider
            logout:
                path: /en/logout
            guard:
                ...

Same for logout actually...

Questioner
vincent PHILIPPE
Viewed
0
Julien B. 2020-11-30 05:12:48

According to this https://symfony.com/doc/current/security.html#logging-out

You can have security.firewalls.main.logout.path referring to a route name. As for login, you can also refer to a route name, but the recommended way to do it is with guard authenticators see https://symfony.com/doc/current/security/form_login.html.

EDIT:

As for the access_control, when I look at the code in Symfony\Component\HttpFoundation\RequestMatcher, it does not look for a route name. So I see two options.

  1. You find a way to create your own RequestMatcher and make Symfony using it, which in my opinion seems overcomplicated for what you need.
  2. Make an entry for every locale in access_control which you are kind of doing right now. For better readability, I would normally put every entry on its own line instead of using regex or like you do, but that's just me.