User Role based routes in Symfony - symfony

I've got five types of roles in my Symfony project.
I want to create restrictions for each role, so that they will have access to specific routes. They will not be able to access others paths. I want to do this in an efficient way like Laravel uses middleware in the routes for access. Is there any way like this in Symfony?

You could do that in different ways, and it depends on your Symfony version.
In the older Symfony versions, the most common way to restrict access to certain routes is adding into config/packages/security.yaml some parameters such as:
access_control:
- { path: '^/agent', roles: ROLE_AGENT }
- { path: '^/profile', roles: ROLE_USER }
- { path: '^/admin', roles: ROLE_ADMIN }
- { path: '^/admin/statistics', roles: ROLE_SUPER_ADMIN }
Also, it's good practice to define the role hierarchy into the same file config/packages/security.yaml :
`role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_ADMIN`
Hence, the users with a SUPER_ADMIN_ROLE will have access to routes restricted to ROLE_ADMIN.
However, my recommendation is if you've several parts to restrict define the general access roles into the config/packages/security.yaml file such as and define a role hierarchy as I said before:
access_control:
- { path: '^/admin', roles: ROLE_ADMIN }
- { path: '^/profile', roles: ROLE_USER }
Then restrict the other routes using annotations thanks to SensioFrameworkExtraBundle, for example:
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
/**
* Require ROLE_ADMIN_SYSTEMS for *every* controller method in this class.
*
* #IsGranted("ROLE_ADMIN_SYSTEMS")
*/
public function YourFunction() { }
For more information look into official Symfony Docs that are very clear. Symfony Security official documentation
I hope this could help you, if you've any other doubts just tell me,
Kind regards.

Related

Symfony4 Two authentification methods in security

I want two authentications methods in my application.
One for the entity User, and other (admin) with a plaintext.
Very simple.
Thus, when I configure security.yaml, I specify the providers:
security:
providers:
user:
entity:
class: App\Entity\User
property: username
in_memory:
memory:
users:
admin:
password: admin
roles: 'ROLE_ADMIN'
encoders:
App\Entity\User: bcrypt
Symfony\Component\Security\Core\User\User: plaintext
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
admin:
provider: in_memory
pattern: ^/admin/
guard:
provider: in_memory
form_login:
login_path: admin_login
check_path: admin_login
logout:
path: /admin/logout
target: /
default:
provider: user
anonymous: ~
guard:
provider: user
form_login:
login_path: login
check_path: login
default_target_path: login_redirect
use_referer: true
logout:
path: /logout
target: /
access_control:
- { path: ^/admin/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin, roles: ROLE_ADMIN }
- { path: ^/dashboard, roles: ROLE_USER }
And return the error:
In GuardAuthenticationFactory.php line 121:
Because you have multiple guard configurators, you need to set the "guard.e
ntry_point" key to one of your configurators ()
Then, if I have to set the guard.entry_point, I need do something like this:
admin:
entry_point: app.form_admin_authenticator
main:
entry_point: app.form_user_authenticator
And therefore, if I undestard, I need to configure a Authentication Listener like this: https://symfony.com/doc/current/components/security/authentication.html
(btw, this particular help page is very ambiguous and incomplete)
Is it necessary? It seems too complex for my purpose
I ran into this particular error. My situation might be a little different, but I had a similar need to authenticate using different authentication strategies depending on the entry point to the application.
One thing your config doesn't include is a reference to any Guard Authenticator objects. See this documentation for an intro to what role those objects play, and how to define them. Symfony's Security package is pretty complicated, and I found that using Guard Authenticators made the process a lot simpler for my use case.
Here is an example of a security.yaml config referencing two different authenticators. The entry_point configuration tells Symfony which one to try first, because in my particular case, Symfony otherwise wouldn't know which authentication strategy to apply first to an incoming request.
security:
providers:
user:
id: App\My\UserProviderClass
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: ~
logout:
path: app_logout
guard:
entry_point: App\My\MainAuthenticator
authenticators:
- App\My\MainAuthenticator
- App\My\OtherAuthenticator
Custom Guard Authenticators contain a method called supports. This method takes the incoming request as its only argument, and returns true or false based on whether the given authenticator should be applied to the incoming request. A common practice might be to check the request's Symfony route name (as defined by the controller) or perhaps something like the full URI for the request. For example:
/**
* Does the authenticator support the given Request?
*
* If this returns false, the authenticator will be skipped.
*
* #param Request $request
*
* #return bool
*/
public function supports(Request $request): bool
{
$matchesMyRoute = 'some_route_name' ===
$request->attributes->get('_route');
$matchesMyUri = '/path/to/secured/resource' ===
$request->getUri();
return $matchesMyRoute || $matchesMyUri;
}
You can imagine that if multiple Guard Authenticators exist in the same application, it's likely the case that one would only want them to apply to a request of a certain type, whether the differentiation is based on the kind of auth applied (eg. a header with an API key vs. a stateful session cookie), whether the difference is more about the specific route being hit, or perhaps a combination of factors.
In this case, telling Symfony which Guard Authenticator to try first may be important for your security strategy, or may have performance ramifications. For example, if you had two authenticators, and one had to hit the database to verify a stateful session, but another could verify the request's authentication statelessly, eg. by verifying a JWT's signature, you'd probably want to make the JWT authenticator run first, because it might not need to make a round trip to the database to authenticate the request.
See this article for a deeper explanation: https://symfonycasts.com/screencast/symfony-security/entry-point

Symfony 4 fosuserbundle

I begin with Symfony 4 and I want to install FosUserBundle with this link :
https://symfony.com/doc/master/bundles/FOSUserBundle/index.html
First :
My problem is that I don't know where to find the "app/config/config.yml" file to uncomment the translator and to configure :
fos_user:
db_driver: orm # other valid values are 'mongodb' and 'couchdb'
firewall_name: main
user_class: AppBundle\Entity\User
from_email:
address: "%mailer_user%"
sender_name: "%mailer_user%"
Second :
I think that I have to create the security.yml file in "config/packages/" directory, is that right ?
Third :
And in which file to add the route ?
Could you help me, please ? :)
I've resolved the problem followed this:
download FOSUserBundle using composer:
composer require friendsofsymfony/user-bundle "~2.0"
At the end of the installation you will have the following error message :
The child node "db_driver" at path "fos_user" must be configured.
Create your User class
Create src/Entity/User.php as custom user class who extend the FOSUserBundle BaseUser class.
<?php
//src/Entity/User.php
namespace App\Entity;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="fos_user")
*/
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
public function __construct()
{
parent::__construct();
// your own logic
}
}
Configure your application's security.yml
Modify config/packages/security.yaml to setup FOSUserBundle security
security:
encoders:
FOS\UserBundle\Model\UserInterface: bcrypt
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_ADMIN
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
fos_userbundle:
id: fos_user.user_provider.username
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_token_generator: security.csrf.token_manager
logout: true
anonymous: true
# 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: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/, role: ROLE_ADMIN }
Configure the FOSUserBundle
Create a new file config/packages/fos_user.yaml for the configuration of FOSUserBundle
fos_user:
db_driver: orm # other valid values are 'mongodb' and 'couchdb'
firewall_name: main
user_class: App\Entity\User
from_email:
address: "vincent#vfac.fr"
sender_name: "vincent#vfac.fr"
Update config/packages/framework.yaml to add templating configuration
framework:
templating:
engines: ['twig', 'php']
Import FOSUserBundle routing
Create config/routes/fos_user.yaml
fos_user:
resource: "#FOSUserBundle/Resources/config/routing/all.xml"
Update your database schema
If not already done, you must create your database
php bin/console doctrine:database:create
Update the schema with the informations from your User class entity
php bin/console doctrine:schema:update --force
At this point, all is installed and configured to use FOSUserBundle in Symfony 4. Run the following command to check if all is ok
composer update
If you don't have any error message, you can test !
You can run the web server to test your application
php bin/console server:start
all tutorial here:
https://vfac.fr/blog/how-install-fosuserbundle-with-symfony-4
This is the solution I found to work.
First:
app/config/config.yml doesn't exist anymore instead the configs have been moved to the config folder. For the FOS User Bundle the correct location: /config/packages/fos_user.yaml. As already noted, use the dev-master version FOSUserBundle, it supports 4(still a little work in progress but good enough).
Second:
You are correct, a simple solution is do a composer require security and the recipe will take care of that for you.
https://symfony.com/doc/current/security.html for more info.
Third:
The default FOS User Bundle routes:
fos_user:
resource: "#FOSUserBundle/Resources/config/routing/all.xml"
More info on the FOS routing (step 6)is helpful
https://symfony.com/doc/master/bundles/FOSUserBundle/index.html
Also, I recommend looking at the yaml samples in symfony routing documentation. It may make things a little more clear when configuring the routes with relation to FOS User Bundle.
https://symfony.com/doc/current/routing.html
ok i have same problem and it should be like that
first:as #sean Baharmi says you should create /config/packages/fos_user.yaml and inter configuration like this
fos_user:
db_driver: orm
firewall_name: main
user_class: App\Entity\Users
from_email:
address: "hello#youmail.com"
sender_name: "Sender Name"
then in framework.yaml you should enter following because of FOSUserBundle dependencies
templating:
engines: ['twig', 'php']
also for add routing in /config/rourtes/routes.yaml add
fos_user:
resource: "#FOSUserBundle/Resources/config/routing/all.xml"
then it is ready to work
hope works for you
You can't use FOSUSerBundle on Symfony4 at the moment. Support has not been merged yet. You can follow development here.
If you want to use FOSUserBundle with Symfony4 you can try the patch Ryan provided here.

Install FOS UserBundle

I'm following a tutorial to install this FOSUserBundle to my project.
I got my information from this french tutorial: http://www.tutodidacte.com/symfony2-installer-fosuserbundle
So I did those commands:
php ./composer.phar require friendsofsymfony/user-bundle "~2.0#dev"
php composer.phar update
Then I created a new Bundle,
php bin/console generate:bundle
Bundle Namespace : Kingdom/UserBundle
But after doing that, in the AppKernel i can see the new UserBundle, mais the FOSUserBundle isn't here.
I try to add it by myself writting it in the file; but after when i try to create an entity we can see something is clearly wrong.
Sorry for the presentation of this below...I haven't succeed to print it correctly.
php bin/console generate:doctrine:entity
Fatal error: Uncaught exception 'Symfony\Component\Config\Definition\Exception\I
nvalidConfigurationException' with message 'The child node "db_driver" at path "
fos_user" must be configured.' in C:\wamp\www\Kingdom\vendor\symfony\symfony\src
\Symfony\Component\Config\Definition\ArrayNode.php:240
Stack trace:
0 C:\wamp\www\Kingdom\vendor\symfony\symfony\src\Symfony\Component\Config\Defin
ition\BaseNode.php(303): Symfony\Component\Config\Definition\ArrayNode->finalize
Value(Array)
1 C:\wamp\www\Kingdom\vendor\symfony\symfony\src\Symfony\Component\Config\Defin
ition\Processor.php(37): Symfony\Component\Config\Definition\BaseNode->finalize(
Array)
2 C:\wamp\www\Kingdom\vendor\symfony\symfony\src\Symfony\Component\Config\Defin
ition\Processor.php(50): Symfony\Component\Config\Definition\Processor->process(
Object(Symfony\Component\Config\Definition\ArrayNode), Array)
3 C:\wamp\www\Kingdom\vendor\friendsofsymfony\user-bundle\DependencyInjection\F
OSUserExtension.php(51): Symfony\Component\Config\Definition\Processor->processC
onfigur in C:\wamp\www\Kingdom\vendor\symfony\symfony\src\Symfony\Component\Conf
ig\Definition\ArrayNode.php on line 240
It seems you haven't properly configured the bundle. Follow the steps here:
http://symfony.com/doc/current/bundles/FOSUserBundle/index.html
In your case, it seems you are missing at least this:
http://symfony.com/doc/current/bundles/FOSUserBundle/index.html#step-5-configure-the-fosuserbundle
EDIT: After reading your question again, it seems you're not loading the bundle properly, as described here:
http://symfony.com/doc/master/bundles/FOSUserBundle/index.html#step-2-enable-the-bundle
After Installation A bundle needs to be enabled in AppKernel.php file. FOSUserBundle needs a bit of configuration to make it work properly I have written a simple and easy guide on it:
https://www.cloudways.com/blog/implement-fosuserbundle-in-symfony-3-1/
Installation:
composer require friendsofsymfony/user-bundle "~2.0#dev"
Enabling Bundle in AppKernel.php
After installing FOSUserBundle you must enable it in the project. Go to app/config/AppKernel.php and add the highlighted line in the bundles array.
$bundles = [
...
new FOS\UserBundle\FOSUserBundle(),
]
Create User Entity
Create the User entity as you are creating above :)
Configuring Security.yml file
security:
encoders:
FOS\UserBundle\Model\UserInterface: bcrypt
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_ADMIN
providers:
fos_userbundle:
id: fos_user.user_provider.username
firewalls:
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_token_generator: security.csrf.token_manager
# if you are using Symfony < 2.8, use the following config instead:
# csrf_provider: form.csrf_provider
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: ^/admin/, role: ROLE_ADMIN }
Configure FOSUserBundle in a Config
Add this config in config.yml
fos_user:
db_driver: orm
firewall_name: main
user_class: AppBundle\Entity\User
Importing Route files of FOSUserBundle
Add this to import routes in Routing.yml
fos_user:
resource: "#FOSUserBundle/Resources/config/routing/all.xml"
Updating Database Schema
The last step is to update the database schema to create table in the database.
php bin/console doctrine:schema:update --force
Now move to the app URL add /login in it you will see the login page.

Allow anonymous access to specific URL in Symfony firewall protected bundle

I have a Symfony bundle which can only be accessible by using mydomain.com/box
To access /box you must be logged in, however i would like to enable anonymous access into mydomain.com/box/download
# Security.yml
access_control:
- { path: ^/box , roles: ROLE_USER}
How can i do ?
# security.yml
access_control:
- { path: ^/box/download , roles: IS_AUTHENTICATED_ANONYMOUSLY}
- { path: ^/box , roles: ROLE_USER}
Symfony2 firewalls are processed in order, and only first matching one will be applied. Therefore, if you put the /box/download before /box, the /box/download rule will be processed and the rest will be ignored.
http://symfony.com/doc/current/book/security.html
Symfony 6
As of Symfony 6 you need to use the role PUBLIC_ACCESS instead of IS_AUTHENTICATED_ANONYMOUSLY.
https://symfony.com/doc/6.0/security.html#allowing-unsecured-access-i-e-anonymous-users

In Symfony2 (v2.3.4) - FOSUserBundle conflicts with Controller Route generated by CRUD

First of all im still learning so don't be angry at me for asking this question (and for my English - im trying my best).
Im going through book tutorial which is written for Symfony 2.0.10, but for each exercise i'm using newest Symfony 2.3.4 project, solving out eventually changes (learning that way) with a good results but finally i'm stuck.
The problem is that the point of exercise is to "make an app which is accessible only for logged users" using FOSUserBundle and CRUD panel. (without registering and all that unnecessary stuff)
Like in the tutorial, i created a bundle (My/BackendBundle), deleted its controller and views, then i created a entity called MyBackendBundle:Mountain and populate db with my data. Next i created CRUD panel for entity i've created before, so the new controller appears wth all those "show", "new" "edit" etc methods. The important thing is that generated controller class (which is named MountainController because of "MyBackendBundle:Mountain" entity) have this #Routing annotation before class:
/**
* Mountain controller.
*
* #Route("/mountain")
*/
class MountainController extends Controller
{
...
But tutorial ordered to delete this annotation in order to use simply Project/web/ address instead of Project/web/mountain. so i did.
Then i created and admin account and change my routing.yml to looks like this:
routing.yml
my_backend:
resource: "#MyBackendBundle/Controller/"
type: annotation
prefix: /
fos_user_security:
resource: "#FOSUserBundle/Resources/config/routing/security.xml"
Next step of tut is to modify the security.yml to looks like this:
security.yml
security:
encoders:
FOS\UserBundle\Model\UserInterface: sha512
#role_hierarchy:
# ROLE_ADMIN: ROLE_USER
# ROLE_SUPER_ADMIN: ROLE_ADMIN
providers:
fos_userbundle:
id: fos_user.user_provider.username
#id: fos_user.user_manager
firewalls:
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_provider: form.csrf_provider
# the user is redirected here when he/she needs to login
login_path: /login
# if true, forward the user to the login form instead of redirecting
use_forward: false
# submit the login form here
check_path: /login_check
# by default, the login form *must* be a POST, not a GET
post_only: true
#remember_me: false
# login success redirecting options (read further below)
always_use_default_target_path: false
default_target_path: /
target_path_parameter: _target_path
use_referer: false
# login failure redirecting options (read further below)
failure_path: null
failure_forward: false
# field names for the username and password fields
username_parameter: _username
password_parameter: _password
# csrf token options
csrf_parameter: _csrf_token
intention: authenticate
logout: true
anonymous: true
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, role: ROLE_ADMIN }
Next steps is about to add logout link to base.html.twig and to override the login page, but this probably doesn't matter because problems already started. When i try to run my app i've got Unable to find Mountain entity. exception. which is pointed to this function in MountainController:
/**
* Finds and displays a Mountain entity.
*
* #Route("/{id}", name="mountain_show")
* #Method("GET")
* #Template()
*/
public function showAction($id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('MyBackendBundle:Mountain')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Mountain entity.');
}
$deleteForm = $this->createDeleteForm($id);
return array(
'entity' => $entity,
'delete_form' => $deleteForm->createView(),
);
}
I'm almost sure it has something to do with the #Route("/{id}", name="mountain_show") annotation which is generated by CRUD because the "login_path" from security.yml which is "/login" fits to #Route pattern of showAction. So the action instead of getting the id of record to show (which should be a number), receives an text or i don't know what, and tries to find id with negative results.
Ps. The example from tutorial (on Symfony 2.0.10) working because the "showAction" generated by CRUD has route: #Route("/{id}/show", name="mountain_show")
which isn't conflicts.
So if there is anybody who can help me with this i will be very appreciated.
If there is any more info i can give to better explain my problem just say. Regards. KB
symfony's routing will try to match the first matching route found ... in your case the other controller's annotation routes are configured before/above FOSUserBundle's ones ... Therefore symfony will first try to match /{id} and then /login.
just move FOSUserBundle's routes before your other controller's route in your configuration to fix this issue.

Resources