Symfony security: Access control rules break after Symfony 6.1 update - symfony

I recently upgraded a Symfony 5.4 project to 6.1. After the upgrade I can't open the start page anymore. The /login page and logging in with a user still works.
The error shown on any other page is pretty cryptic:
ErrorException: Warning: preg_match(): Compilation failed: unmatched
closing parenthesis at offset 2
at vendor/symfony/http-foundation/RequestMatcher.php:165
at Symfony\Component\HttpFoundation\RequestMatcher->matches(object(Request))
(vendor/symfony/security-http/AccessMap.php:42)
If I comment out all access_control in security.yaml I can navigate around the page again, so I assume the error is somewhere in those rules. I have looked at https://symfony.com/doc/current/security/access_control.html but can't figure out why my config is broken. Is this the source of the error message?
This is my security.yaml:
security:
enable_authenticator_manager: true
password_hashers:
App\Entity\User:
algorithm: auto
providers:
app_user_provider:
entity:
class: App\Entity\User
property: email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
lazy: true
provider: app_user_provider
custom_authenticator: App\Security\LoginFormAuthenticator
logout:
path: security_logout
target: security_login
form_login:
check_path: security_login
login_path: security_login
enable_csrf: true
default_target_path: default_index
entry_point: form_login
access_control:
- { path: ^/login$, roles: PUBLIC_ACCESS }
- { path: ^/registration, roles: PUBLIC_ACCESS }
- { path: ^/resetting, roles: PUBLIC_ACCESS }
- { path: ^/locale, roles: PUBLIC_ACCESS }
- { path: ^/_error, roles: PUBLIC_ACCESS }
- { path: ^/), roles: ROLE_USER }

The error message basically tells you what's wrong.
Your last access_control rule uses a closing parenthesis ")". In Regex this is a reserved character. If this is not a mistake and you actually have routes starting with a closing parenthesis, then you will have to escape the character like so:
- { path: ^/\), roles: ROLE_USER }

Related

API Platform - Swagger UI with JWT Authentication

I'd like to add the "Authorize" button on Swagger, like described here : https://api-platform.com/docs/core/jwt#documenting-the-authentication-mechanism-with-swaggeropen-api
I installed LexikJWTAuthenticationBundle, it works fine with Curl. But when I browse to http://localhost:8000/api, I only see {"code":401,"message":"JWT Token not found"}.
Am I missing something?
Here's my security.yaml:
security:
encoders:
App\Entity\User:
algorithm: bcrypt
providers:
db_provider:
entity:
class: App\Entity\User
property: username
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
api_login:
pattern: ^/api/login
stateless: true
anonymous: true
form_login:
check_path: /api/login_check
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
require_previous_session: false
api:
pattern: ^/api
stateless: true
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
main:
pattern: ^/
anonymous: ~
provider: db_provider
form_login:
login_path: app_security_login
check_path: app_security_login
csrf_token_generator: security.csrf.token_manager
logout:
path: /logout
target: /
remember_me:
secret: '%kernel.secret%'
lifetime: 604800
path: /
access_control:
- { path: ^/admin, roles: ROLE_ADMIN }
- { path: ^/api/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, roles: ROLE_USER }
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
access_decision_manager:
strategy: unanimous
And my api_platform.yaml:
api_platform:
title: 'My project'
version: '0.0.1'
mapping:
paths: ['%kernel.project_dir%/src/Entity']
swagger:
api_keys:
apiKey:
name: Authorization
type: header
Bit late to this, but I faced this same issue. Your security configuration is stating that any route beginning with /api requires authentication, which includes /api itself. If you want to keep the documentation on the /api route, add a trailing slash to the security configuration;
firewalls:
...
api:
pattern: ^/api/
and
access_control:
- { path: ^/api/, roles: IS_AUTHENTICATED_FULLY }
This will leave /api as publicly accessible, whilst requiring a valid token to be provided for /api/*.
Alternatively, you can leave the security configuration as it is and move the documentation to a different URL (e.g. /docs). For this, you may need to add /docs as an IS_AUTHENTICATED_ANONYMOUSLY path under access_control depending on your other rules.
Then when the documentation page is accessible, click the Authorize button at the top of the page and enter Bearer <valid JWT token>.
It's old but here is the solution in 2021
You have to decorate open api factory
Edit :
Don't put hyphen (-) in the name of the authorization and in the scheme key otherwise it won't work (probably other special characters)
In config/packages/api_platform.yaml :
swagger:
versions: [3]
api_keys:
JWT: // The name of the authorization to display on swagger UI
name: Authorization
type: header
In config/services.yaml :
App\OpenApi\JwtDecorator:
decorates: 'api_platform.openapi.factory'
arguments: [ '#App\OpenApi\JwtDecorator.inner' ]
autoconfigure: false
enter code here
The decorating service : in OpenApi\JwtDecorator
class JwtDecorator implements OpenApiFactoryInterface
{
public function __construct(
private OpenApiFactoryInterface $decorated
) {}
public function __invoke(array $context = []): \ApiPlatform\Core\OpenApi\OpenApi
{
$openApi = ($this->decorated)($context);
$schemas = $openApi->getComponents()->getSecuritySchemes();
$schemas['JWT'] = new \ArrayObject([
'type' => 'http',
'scheme' => 'bearer',
'bearerFormat' => 'JWT'
]);
return $openApi;
}
}
I could fix my problem. In my case problem was, in public and private openssl keys. First I fixed it, the second, problem was in encoding. I used the source below to achieve result. Just take a look to link below
LexikJWTAuthenticationBundleSandbox

Symfony3 / FOSUserBundle : /login/ loop

My website is running with Symfony 3.4 and I just install the FOSUserBundle to manage login/authentification. I followed this tutorial but all isn't working perfectly. For the record I can access my homepage view (/app_dev.php/) and my login page view (/app_dev.php/login) but in my security.yml :
In the "main" firewall if "anonymous" is set to "true" : everybody can access all the pages.
In the "main" firewall if "anonymous" is set to "false" :
I don't figure out why this path is making a infinite loop.
Below is my security yaml config :
security:
encoders:
FOS\UserBundle\Model\UserInterface: bcrypt
providers:
fos_userbundle:
id: fos_user.user_provider.username
role_hierarchy:
ROLE_ADMIN: ROLE_USER
firewalls:
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_token_generator: security.csrf.token_manager
logout: true
anonymous: false
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/, role: ROLE_ADMIN }
And in my dev.log, these lines are looped :
[2018-01-15 10:54:24] request.INFO: Matched route
"fos_user_security_login".
{"route":"fos_user_security_login","route_parameters":{"_controller":"FOS\UserBundle\Controller\SecurityController::loginAction","_route":"fos_user_security_login"},"request_uri":"http://www.mycompany.com/app_dev.php/login","method":"GET"}
[] [2018-01-15 10:54:24] security.INFO: An AuthenticationException was
thrown; redirecting to authentication entry point.
{"exception":"[object]
(Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException(code:
0): A Token was not found in the TokenStorage. at
/var/www/custom_pim/vendor/symfony/symfony/src/Symfony/Component/Security/Http/Firewall/AccessListener.php:51)"}
[] [2018-01-15 10:54:24] security.DEBUG: Calling Authentication entry
point. [] []
You have to change anonymous:
anonymous: true
I solved my problem with the following code :
firewalls:
main:
pattern: ^/
form_login:
provider: fos_userbundle
default_target_path: /
csrf_token_generator: security.csrf.token_manager
logout:
target: fos_user_security_login
anonymous: true
access_control:
- { path: ^/$, role: ROLE_USER }
I have checked my settings with yours, and the only thing you have different is
anonymous: false
which I have set to true (which is the default I think). Maybe try changing that and report back, I have a pretty fresh FOSUserBundle project on my hand to check

Redirect anonymous users from restricted areas in Symfony2

I've built a web app using Symfony 2.8 and I've now got to the task of separating the admin area from the front end. I have done that using the following code in the security.yml file:
security:
encoders:
MyApp\Bundle\CoreBundle\Entity\Users:
algorithm: sha512
role_hierarchy:
ROLE_ADMIN: ROLE_BLOCKED
providers:
main:
entity: { class: MyApp\Bundle\CoreBundle\Entity\Users, property: username }
firewalls:
default:
anonymous: ~
secured_area:
pattern: ^/admin
anonymous: ~
access_denied_url: core_login
form_login:
check_path: core_login_check
login_path: core_login
failure_path: core_login
default_target_path: ^/admin/booking/today/
logout:
path: core_logout
target: core_login
access_control:
- { path: ^/admin, roles: 'ROLE_ADMIN' }
- { path: ^/ajax/admin, roles: 'ROLE_ADMIN' }
- { path: ^/ajax/backend, roles: 'ROLE_ADMIN' }
- { path: ^/, roles: 'IS_AUTHENTICATED_ANONYMOUSLY' }
This is working for me in terms of blocking access to the areas I want. However, if the anonymous user tries to access /admin I get the following message:
Full authentication is required to access this resource.
When I do this in the production environment, I just get the standard 500 error.
What I want to have happen is the user be redirected to the login page. This isn't happening at the moment, so what can I do to acheive this?

Redirect after login and logout adds leading slash to URI, which causes exception

I am using FOSUserbundle with the SonataUserbundle. I am not sure, which bundle this error belongs to, but I will try here first. Everytime I login and logout I get redirected:
After logging in, I get redirected to /app_dev.php///dashboard (3 leading slashes)
After logging out, I get redirected to /app_dev.php//login (2 leading slashes)
Here us my security.yml
security:
acl:
connection: default
providers:
fos_userbundle:
id: fos_user.user_provider.username
encoders:
FOS\UserBundle\Model\UserInterface: sha512
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
pattern: ^/.*
context: user
form_login:
provider: fos_userbundle
login_path: sonata_user_admin_security_login
use_forward: false
check_path: /login_check
failure_path: null
logout: true
anonymous: true
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, role: [ROLE_USER] }
access_decision_manager:
strategy: unanimous
Can anybody hint me, what I might be missing?
#stof Owner stof commented 39 minutes ago
The redirection after login is handled by the SecurityBundle, not by
FOSUserBundle (we don't handle the login itself) #stof stof closed
this 39 minutes ago
You have to change target path:
# app/config/security.yml
security:
firewalls:
main:
form_login:
# ...
default_target_path: you_target_path
Read more

I don't understand how to configure my security.yml file for the index page

I developed my symfony2 website with the required authentification (with FOSUserBundle).
Now I have decided to add 2 more exceptions for the anonymous visitors: The index page ("/") and the contact form ("/contact").
When I modify my security.yml, these get broken:
In my twig contact form page, all of my "{% if is_granted("IS_AUTHENTICATED_REMEMBERED") %}" don't work anymore. It is really like I am not authentificated anymore.
In my twig index page, I have the same problem, too.
Here is my security.yml. I know that it can be trivial, but I don't find it in the doc where I can have more information on "keep me connected with authenticated session living" with the security.yml file. Everything I have tried doesn't work.
security:
encoders:
"FOS\UserBundle\Model\UserInterface": sha512
role_hierarchy:
ROLE_AUTHOR: ROLE_USER
ROLE_ADMIN: [ROLE_USER, ROLE_AUTHOR]
providers:
fos_userbundle:
id: fos_user.user_manager
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login:
pattern: ^/(login$|register|resetting)
anonymous: true
token:
pattern: ^/administration/create-user/confirmation-token/
anonymous: true
#this is where it fail....
contact:
pattern: ^/contact$
anonymous: true
index:
pattern: ^/$
anonymous: true
# Main Firewall
main:
pattern: ^/+
form_login:
provider: fos_userbundle
remember_me: true
remember_me:
key: %secret%
anonymous: false
logout: true
#http_basic:
# realm: "Secured Demo Area"
access_control:
#- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https }
#- { path: ^/_internal, roles: IS_AUTHENTICATED_ANONYMOUSLY, ip: 127.0.0.1 }
Thank you in advance
you're doing it wrong :) You need to have only few firewalls. Not each firewall for each url.
do it in this way:
firewalls:
main:
pattern: ^/
switch_user: true
anonymous: ~
form_login:
provider: fos_userbundle
login_path: /login
logout:
path: /logout
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, role: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https }
Next add another items into access_control.
Instead of creating different firewalls for contact and index, you have to add them to access_control, as they should be handled by the same firwall as the rest of your application (main), they only differ in that you want to modify which roles may access them:
main:
pattern: ^/
...
access_control:
- { path: ^/$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/contact$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
#- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https }
#- { path: ^/_internal, roles: IS_AUTHENTICATED_ANONYMOUSLY, ip: 127.0.0.1 }
edit for clarification:
Specifying different firewalls like you did, puts those pages outside of your current security context and therefore the login from firewall main does not apply to these firewalls.

Resources