the symfony security does not protect the route - api

with symfony, I set up a security system with jwt.
I manage to connect and I get the token.
I configured /api to be protected by token so.
only it doesn't protect it. i can access it in fo
security.yaml
security:
enable_authenticator_manager: true
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
App\Entity\User:
algorithm: auto
providers:
app_user_provider:
entity:
class: App\Entity\User
property: email
firewalls:
login:
pattern: ^/api/login
stateless: true
json_login:
check_path: /api/login_check
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
api:
pattern: ~/api
stateless: true
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
access_control:
- { path: ~/api, roles: IS_AUTHENTICATED_FULLY }
- { path: ~/auth/register, roles: PUBLIC_ACCESS }
when#test:
security:
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
algorithm: auto
cost: 4 # Lowest possible value for bcrypt
time_cost: 3 # Lowest possible value for argon
memory_cost: 10 # Lowest possible value for argon
#[Route('/api')]
class DataController extends AbstractController
{
#[Route('/locations', name: 'app_locations', methods: 'GET')]
public function locations(LocationRepository $locationRepository): Response
{
GET http://localhost:8001/api/locations
I get the data, but it should not allow me access.

Your access_control seems to be the issue.
Try editing with:
access_control:
- { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
- { path: ^/auth/register, roles: PUBLIC_ACCESS }
Which should match your /api/locations route.
In your code, you have ~/api which does not match /api/location, that's why we are using ^/api to match anything that follows /api.
You can see more advanced example in the symfony documentation.

Related

JWT authentication configuration (Symfony 5.3.16)

I have an error 'Unable to create a signed JWT from the given configuration.'
Here is my code.
Security.yaml
security:
enable_authenticator_manager: true
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
providers:
# used to reload user from session & other features (e.g. switch_user)
app_user_provider:
entity:
class: App\Entity\User
property: email
firewalls:
login:
pattern: ^/api/login
stateless: true
json_login:
username_path: email
check_path: /api/login_check # or api_login_check as defined in config/routes.yaml
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
api:
pattern: ^/api
stateless: true
jwt: ~
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
lazy: true
provider: app_user_provider
access_control:
- { path: ^/api/login, roles: PUBLIC_ACCESS }
- { path: ^/api, roles: IS_AUTHENTICATED_FULLY }
routes.yaml
api_login_check:
path: /api/login_check
Here are the steps :
symfony new jwt-auth --version=5.3
cd jwt-auth
composer require symfony/maker-bundle --dev
php bin/console doctrine:database:create
composer require orm
composer require security
php bin/console make:user
php bin/console security:hash-password
composer require lexik/jwt-authentication-bundle
php bin/console lexik:jwt:generate-keypair
configure your Security.yaml file
configure your Routes.yaml file
Test API via PostMan
If you can help me it will be great.
Thanks in advance

How to use different authenticators for API and admin of the site

I made a project that is divided into two parts, the front-end part using Vue.js and the back-end part using Symfony and API platform. I did an authentication system on my API platform with JWT tokens like this: https://api-platform.com/docs/core/jwt/ which works like a charm when using it with Vue.js and Axios library.
However, I would like to use the Symfony auth component to create an admin access on my project Symfony, just to allow the admin to create new things and save them in my db. The route will be /admin/whatever. In my security.yaml, I already have a firewall for the API/JWT authentication which looks like this:
enter image description here
How can I use another which handles the "classic" authentication of Symfony so I can have 2 authentication systems independent on each other?
Edit : I tried this :
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login:
lazy: true
provider: app_user_provider
json_login:
check_path: /authentication_token
username_path: email
password_path: password
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
jwt: ~
main:
lazy: true
provider: app_user_provider
custom_authenticator: App\Security\LoginAuthenticator
logout:
path: app_logout
With this access control :
access_control:
- { path: ^/admin, roles: ROLE_ADMIN }
- { path: ^/profil, roles: ROLE_USER }
- { path: ^/authentication_token, roles: PUBLIC_ACCESS }
- { path: ^/api/, roles: IS_AUTHENTICATED_FULLY }
But my /profil route displays this capture
My authentication to the api with token while doing a request still works though
You need to have two different configuration in your security.yaml. For example login for the api connexion and main for your app connection
# API connexion
login:
pattern: ^/api/login$
stateless: true
json_login:
check_path: /api/login
username_path: email
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
# App connection
main:
lazy: true
provider: app_user_provider
# other configuration ...
Edit
I may have found the solution (at least it works) :
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
api:
pattern: ^/api/
stateless: true
provider: app_user_provider
jwt: ~
login:
pattern: ^/authentication_token
json_login:
check_path: /authentication_token
username_path: email
password_path: password
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
main:
lazy: true
provider: app_user_provider
custom_authenticator: App\Security\LoginAuthenticator
logout:
path: app_logout
access_control:
- { path: ^/admin, roles: ROLE_ADMIN }
- { path: ^/profil, roles: ROLE_USER }
- { path: ^/authentication_token, roles: PUBLIC_ACCESS }
- { path: ^/api/, roles: IS_AUTHENTICATED_FULLY }
But I found it nearly randomly, testing a few different configurations, not really knowing what I was doing. So could someone explain me what does this code do exactly ? And why what I tested just before didn't work ? ("/authentication_token" is a route that I call with a POST request, passing it an email and a password and it shall return a token that I use to authenticate for the requests on my api, made with API Platform bundle)

Symfony losing auth session between login and redirect

I have an app that's has a form login which has been working fine.
I then added an api side to it using this guide. Now my log in on the web side doesn't work anymore.
This is my security.yaml file:
security:
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
users:
entity:
class: 'App\Entity\User'
property: 'username'
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
pattern: ^/
anonymous: true
guard:
authenticators:
- App\Security\LoginFormAuthenticator
form_login:
login_path: app_login
check_path: app_login
logout:
path: app_logout
target: app_user_index
secured_area:
form_login:
csrf_token_generator: security.csrf.token_manager
encoders:
App\Entity\User:
algorithm: bcrypt
cost: 12
role_hierarchy:
ROLE_ADMIN: ROLE_USER
# activate different ways to authenticate
# http_basic: true
# https://symfony.com/doc/current/security.html#a-configuring-how-your-users-will-authenticate
# form_login: true
# https://symfony.com/doc/current/security/form_login_setup.html
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
# - { path: ^/delete, roles: ROLE_ADMIN }
# - { path: ^/profile, roles: ROLE_USER }
I'm not sure what else I need to post, but I can't think of any other thing that might have changed that could cause it to break.
If I revert to a point before implementing the API, login works fine again.
What could be the issue?
Try comparing the file before and after to see the differences.
Have you checked the logs? Are you getting an error?
As the article talks about changing a number of different files, it's hard to tell. I.e. Your file posted does not contain any of the stuff in the article, like the ^/api firewall
Maybe create the skeleton line for line in the article in a separate folder, then compare with your project, file by file, adding the skeleton stuff...
It seems like you are not telling your main firewall which provider to use for authentication, so your api one could be overriding it...
I.e. Your main: form_login: provider: needs to be users, and your api can use the fos_user bundle
Both should be able to use the same provider for with as long as the field names are the same
Edit:
1) Checkout symphony firewalls and access control
2) Decide whether you want the same users as your main site, or a different user provider for the api
3) Point the form_login in the relevant section of the firewall to the user provider you want to use
Above you have one provider registered, "users" in the provider section.
Assuming you wanted separate users to your main site:
If you followed the article, you would have put "fos_userbundle" as another provider in that section, and added the firewall sections to allow oauth for the api. Under "form_login" on "aouth_authorize" there is a provider that points to the fos_userbundle. You should have also added the api route to control which route your api responds to (pattern: ^/api <== any route starting with api)
I suspect your user provider under the main section now doesn't know which user bundle to use to authenticate. i.e. have you tried to login as an api user on your main site? Does it authenticate? If so, you need to tell your "main" section in the firewall, that the user provider must be the "users" provider by adding provider: users to the "form_login" section of the firewall.
If you want to use a separate user provider for your main site and your api:
(untested code)
security:
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
users:
entity:
class: 'App\Entity\User'
property: 'username'
fos_userbundle:
id: fos_user.user_provider.username
firewalls:
oauth_token:
pattern: ^/oauth/v2/token
security: false
oauth_authorize:
pattern: ^/oauth/v2/auth
form_login:
provider: fos_userbundle
check_path: /oauth/v2/auth_login_check
login_path: /oauth/v2/auth_login
use_referer: true
api:
pattern: ^/api
fos_oauth: true
stateless: true
anonymous: false
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
pattern: ^/
anonymous: true
guard:
authenticators:
- App\Security\LoginFormAuthenticator
form_login:
provider: users
login_path: app_login
check_path: app_login
logout:
path: app_logout
target: app_user_index
secured_area:
form_login:
csrf_token_generator: security.csrf.token_manager
encoders:
App\Entity\User:
algorithm: bcrypt
cost: 12
FOS\UserBundle\Model\UserInterface: bcrypt
role_hierarchy:
ROLE_ADMIN: ROLE_USER
# activate different ways to authenticate
# http_basic: true
# https://symfony.com/doc/current/security.html#a-configuring-how-your-users-will-authenticate
# form_login: true
# https://symfony.com/doc/current/security/form_login_setup.html
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
# - { path: ^/delete, roles: ROLE_ADMIN }
# - { path: ^/profile, roles: ROLE_USER }
- { path: ^/api, roles: [ IS_AUTHENTICATED_FULLY ] }
If you want to use the same provider for the main site and the api:
(untested code)
security:
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
users:
entity:
class: 'App\Entity\User'
property: 'username'
firewalls:
oauth_token:
pattern: ^/oauth/v2/token
security: false
oauth_authorize:
pattern: ^/oauth/v2/auth
form_login:
provider: users
check_path: /oauth/v2/auth_login_check
login_path: /oauth/v2/auth_login
use_referer: true
api:
pattern: ^/api
fos_oauth: true
stateless: true
anonymous: false
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
pattern: ^/
anonymous: true
guard:
authenticators:
- App\Security\LoginFormAuthenticator
form_login:
provider: users
login_path: app_login
check_path: app_login
logout:
path: app_logout
target: app_user_index
secured_area:
form_login:
csrf_token_generator: security.csrf.token_manager
encoders:
App\Entity\User:
algorithm: bcrypt
cost: 12
role_hierarchy:
ROLE_ADMIN: ROLE_USER
# activate different ways to authenticate
# http_basic: true
# https://symfony.com/doc/current/security.html#a-configuring-how-your-users-will-authenticate
# form_login: true
# https://symfony.com/doc/current/security/form_login_setup.html
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
# - { path: ^/delete, roles: ROLE_ADMIN }
# - { path: ^/profile, roles: ROLE_USER }
- { path: ^/api, roles: [ IS_AUTHENTICATED_FULLY ] }

Symfony User getting disconencted on deployment

Deploying my application on my server, i have issues :
When i log my user manually it works fine, when i go to profile, edit, it works ! !
BUT
WHEN i go to a page non-handled by FOSUserBundle, my user is not logged in anymore ...
$token = new UsernamePasswordToken($user, $user->getPassword(), $providerKey, $user->getRoles());
$userProvider = new UserProvider($this->get('fos_user.user_manager'));
$this->get("security.token_storage")->setToken($token);
$event = new InteractiveLoginEvent($request, $token);
$this->get("event_dispatcher")->dispatch("security.interactive_login", $event);
But in local it's working ....
If you have any idea ... would be glad, thx !!
EDIT :
here is my security.yml
# app/config/security.yml
security:
encoders:
Canapey\UserBundle\Entity\User: sha512
role_hierarchy:
ROLE_USER: [ROLE_USER]
# Un admin hérite des droits d'auteur et de modérateur
ROLE_ADMIN: [ROLE_USER, ROLE_MODERATEUR]
# On garde ce rôle superadmin, il nous resservira par la suite
ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
main:
id: fos_user.user_provider.username_email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
pattern: ^/
anonymous: true
provider: main
form_login:
login_path: fos_user_security_login
check_path: fos_user_security_check
csrf_token_generator: security.csrf.token_manager
always_use_default_target_path : true
logout:
path: fos_user_security_logout
target: /
remember_me:
secret: "%secret%" # %secret% est un paramètre de parameter
always_remember_me: true
access_control:
- { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/login$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, roles: IS_AUTHENTICATED_ANONYMOUSLY }
Shortly: get the path of your sessions in config.yml:
framework:
...
session:
...
save_path: ...
and make sure it's not changed / emptied during deploy.
Details
Most deploy systems clean all work folders (e.g. cache, tmp, sessions) during deploy, or even use a release-based structure where the actual root is created from scratch each time and soft-linked to a current directory (see e.g. Capistrano: http://capistranorb.com/documentation/getting-started/structure/).
In these situations, sessions are destroyed during deploy so of course you get logged out.

Two separate login pages in Symfony 2

I'm trying to figure out how to have two separate login pages: a default login for the .com page and one for specific users, for example for the route /special.
Is this easily possible with in one SF2 project?
UPDATE:
I have the following configuration in my firewall (I'm using fosub)
providers:
custom:
id: ib.user_provider
fos_userbundle:
id: fos_user.user_manager
my_fos_facebook_provider:
id: my.facebook.user
firewalls:
special:
pattern: ^/special
form_login:
provider: fos_userbundle
login_path: /special/login
check_path: /special/login_check
use_referer: false
default_target_path: /special
success_handler: ib.login_handler
provider: custom
main:
pattern: ^/.*
form_login:
provider: fos_userbundle
login_path: /login
check_path: /login_check
use_referer: false
default_target_path: /
provider: custom
fos_facebook:
always_use_default_target_path: true
app_url: "http://apps.facebook.com/%facebook_app_id%/"
server_url: "http://aw.com/aw/web/app_dev.php/"
login_path: /login
check_path: /login_check/facebook
default_target_path: /checkFB
success_handler: facebook_auth_success_handler
provider: my_fos_facebook_provider
logout:
#handlers: ["fos_facebook.logout_handler"]
target: /
anonymous: ~
In the ib.login_handler I have the following:
public function onAuthenticationSuccess(Request $request,TokenInterface $token)
{
if ($this->security->isGranted('ROLE_CATEGORIZER'))
{
$response = new RedirectResponse($this->router->generate('MyCoBundle_mailAdmin_index'));
}
return $response;
}
With this configuration if I go to mydomain.com/special I get the following error: Fehler: Umleitungsfehler (in english: Error: Redirection error)
UPDATE:
in chrome I get: No route found for "GET /special/login"
404 Not Found - NotFoundHttpException
1 linked Exception: ResourceNotFoundException »
I don't have a special route for this login path. What I want to achieve is just, that a special user has only access to pages under the path / special.
It's possible, you can define many protected zones => many firewalls.
Let's see this app/config/security.yml configuration to know how :
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
special_area:
pattern: ^/special
anonymous: ~
form_login:
check_path: /special/login_check
login_path: /special/login
logout:
path: /special/logout
target: /
general_area:
pattern: ^
anonymous: ~
form_login:
check_path: /login_check
login_path: /login
logout:
path: /logout
target: /
access_control:
- { path: ^/_internal, role: IS_AUTHENTICATED_ANONYMOUSLY, ip: 127.0.0.1 }
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/special/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
Beware that special_area must be defined above genereal_area because general_area's pattern matches every other ones...
What you must add in your bundle routing.yml :
_security_login_special:
pattern: /special/login
defaults: { _controller: FOSUserBundle:Security:login }
_security_check_special:
pattern: /special/login_check
_security_logout_special:
pattern: /special/logout
And you have to add another role for general_area, so you need to override FOSUserManager and make it add this supplementary role on user loading... (More information here : https://github.com/FriendsOfSymfony/FOSUserBundle/blob/1.2.0/Resources/doc/user_manager.md)