guys!
I'am trying to configure user system (FOSUserBundle) for my Symfony app. All was going Ok until I tried to allow access to whole site and restrict access to some routes using access control in security configuration file.
firewalls:
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_provider: form.csrf_provider
default_target_path: /
logout: true
anonymous: true
access_control:
- { path: ^/$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/profile$, roles: ROLE_USER }
- { path: ^/admin$, roles: ROLE_ADMIN }
I've tried also
#
- { path: ^/.*, roles: IS_AUTHENTICATED_ANONYMOUSLY }
#
and when i go to index page (/), it redirects me to login page. I want to have index page visible for all visitors, not only for those who logged in.
Just can't figure out this moment. Thank you for answers.
try this:
access_control:
- { path: ^/profile$, roles: ROLE_USER }
- { path: ^/admin$, roles: ROLE_ADMIN }
- { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY }
Your problem may be related to trying to specify the role as an array of role but you give only one value:
- { path: ^/*, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/profile$, role: ROLE_USER }
- { path: ^/admin$, role: ROLE_ADMIN }
for more roles you need the []
I resolved the issue. Sorry for my dumbness, i've been wandering for 2 days why this happen.
Redirect was from controller. My mistake, sorry. Thank you for answers anyway.
public function startAction()
{
$user = $this->getUser();
if ($user) {
return $this->render('HellfireCommonBundle:Index:index.html.twig', array('user' => $user));
} else {
return $this->redirect($this->generateUrl('fos_user_security_login'));
}
}
Related
I want to separate the admin login page and user login page. I did it this way with the codes I got from some sources, but I get an error.
// config/security.yaml
security:
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
encoders: ...
role_hierarchy: ...
# 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:
...
admin:
pattern: /admin(.*)
form_login:
provider: fos_userbundle
login_path: /admin/login
check_path: /admin/login_check
default_target_path: /admin/
logout:
path: /admin/logout
target: /admin/login
anonymous: true
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 }
- { path: ^/admin/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/logout$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/login_check$, role: IS_AUTHENTICATED_ANONYMOUSLY }
The routes.yaml file is as follows.
admin_login:
path: /admin/login
defaults: { _controller: App\UserBundle\Controller\SecurityController }
and The SecurityController file is as follows.
<?php
namespace App\UserBundle\Controller;
use FOS\UserBundle\Controller\SecurityController as BaseController;
class SecurityController extends BaseController
{
public function renderLogin(array $data)
{
$requestAttributes = $this->container->get('request')->attributes;
if ('admin_login' === $requestAttributes->get('_route')) {
$template = sprintf('admin/Security/login.html.twig');
} else {
$template = sprintf('#FOSUser/Security/login.html.twig');
}
return $this->container->get('templating')->renderResponse($template, $data);
}
}
I wrote this way, but when I enter the admin / login page, I get an error like the one below.
This page isn’t working
127.0.0.1 redirected you too many times.
ERR_TOO_MANY_REDIRECTS
How can I fix this error.
You are having too many redirect because symfony is reading top to bottom and /admin/ is written before /admin/login or /admin/login_check so it will match with this access control.
Access control (Symfony):
For each incoming request, Symfony checks each access_control entry to
find one that matches the current request. As soon as it finds a
matching access_control entry, it stops - only the first matching
access_control is used to enforce access.
So you need to put your /admin_login before your /admin
Update your access control with something like :
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/logout$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/login_check$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/, role: ROLE_ADMIN }
I have a Symfony 3 CRM with FOS User Bundle installed for the login. The issue is, most users of this CRM will be engineers belonging to a company who are only allowed to see certain parts, so I have created their own dashboard specifically. Admin users can see everything and simply redirect to the main dashboard. However, it seems that only users with ROLE_ADMIN are allowed to access the CRM and everyone else is denied regardless of where they go.
Here is my security file:
security:
encoders:
FOS\UserBundle\Model\UserInterface: bcrypt
role_hierarchy:
ROLE_STAFF: ROLE_USER
ROLE_ADMIN: ROLE_STAFF
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
use_referer: false
success_handler: login_success_handler
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_ADMIN }
- { path: ^/staff-dashboard, role: ROLE_STAFF }
As you can see I have created a custom role called ROLE_STAFF which is assigned to engineers (or staff members) and they are allowed to view the staff-dashboard link. I have a test user with the ROLE_STAFF role but I still am unable to view staff-dashboard.
I also have the following if statement in my controller, so it redirects all those users who are NOT admin to the staff-dashboard:
if($userRole === "ROLE_ADMIN") {
return $this->render('AppBundle:pages:dashboard.html.twig', array(
'latest' => $latest,
'cashflow_chart' => $ob,
'job_chart' => $ob2
));
} else {
return $this->redirectToRoute('app_staff_dashboard');
}
But again, this does not work.
Any help with this is appreciated - I haven't yet found a solid solution.
Access control rules are processed in order specified in config. First matched rule (matched path) is checked and processing stops.
For your case 2 rules match path /staff-dashboard: 1 - { path: ^/, role: ROLE_ADMIN } and 2 - { path: ^/staff-dashboard, role: ROLE_STAFF }. The 1-st one is checked. Staff users don't pass this rule.
Change the order of these 2 rules.
I am using the FOSOAuthBundle for my REST application
I would like most of my routes to require authorization however there are a few that should have public access
I have the following in my security.yml:
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:
oauth_token:
pattern: ^/login
security: false
api:
pattern: ^/
fos_oauth: true
stateless: true
anonymous: false
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, roles: [ IS_AUTHENTICATED_FULLY ] }
For example:
I have a Products Entity and Controller
I would like the CRUD operations to be private except for Read
So: POST, PUT, DELETE on /products(/:id) should be private while GET should be public.
I have tried adding the following to the access_control:
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/products$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, roles: [ IS_AUTHENTICATED_FULLY ] }
I thought this would open up all methods on /products but I get the error:
{
"error": "access_denied",
"error_description": "OAuth2 authentication required"
}
I have many entities and controllers I am trying to apply this to.
How would I go about opening up specific routes (including the method requirements)?
You can make new firewall with regex and set it like this. You have to put it in front of your api firewall in order to match this regex first.
api_anonym_area:
pattern: (^/api/products/.*)
methods: [GET]
security: false
Or you can make it
api_anonym_area:
pattern: (^/api/products/.*)
methods: [GET]
anonymous: true
with
access_control:
- { path: ^/api/products/.*, role: IS_AUTHENTICATED_ANONYMOUSLY}
In first case you wont have token, in in second case you will have token (its good when you expect authenticated or anonymous users to come).
To achieve this, best way would be to code the permissions in the controllers, I don't think this is possible via the security.yml configuration.
You should remove:
- { path: ^/, roles: [ IS_AUTHENTICATED_FULLY ] }
And manage permissions inside the controller actions, for example (taken from symfony documentation at http://symfony.com/doc/current/security.html)
public function updateProduct($id)
{
// The second parameter is used to specify on what object the role is tested.
$this->denyAccessUnlessGranted('ROLE_ADMIN', null, 'Unable to access this page!');
// Old way :
// if (false === $this->get('security.authorization_checker')->isGranted('ROLE_ADMIN')) {
// throw $this->createAccessDeniedException('Unable to access this page!');
// }
// ...
}
I encountered a strange issue. I have the following security.yml:
security:
encoders:
Symfony\Component\Security\Core\User\User: plaintext
role_hierarchy:
ROLE_USER:
ROLE_EDITOR: [ROLE_USER]
ROLE_ADMIN: [ROLE_USER, ROLE_EDITOR]
providers:
in_memory:
memory:
users:
admin: { password: 123456, roles: [ 'ROLE_ADMIN' ] }
editor: { password: 123456, roles: [ 'ROLE_EDITOR' ] }
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
backend:
pattern: ^/backend
anonymous: ~
provider: in_memory
form_login:
login_path: backend_login
check_path: backend_login_check
access_control:
- { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY, host: example\.com$ }
- { path: ^/backend_login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/backend, roles: ROLE_ADMIN }
- { path: ^/user/fetch, roles: ROLE_USER }
- { path: ^/level, roles: ROLE_USER }
- { path: ^/gallery, roles: ROLE_USER }
I have an window development machine with XAMPP running and everything works out properly. I can log in to the backend and if I'm not logged in and try to open a backend route, I'm redirected to the login page.
This is my routing portion:
backend_login:
pattern: /backend_login
defaults: { _controller: FooBackendBundle:Security:login }
backend_login_check:
pattern: /backend/login_check
But when I'm uploading it to my integration linux server, I can open the backend without having to log in. It seems like Symfony does not care about the role the current user has.
The code and the symfony version are both the exact same (Symfony 2.3).
If I remove the anonymous: ~ part from the backend firewall, it will redirect to the login page, but also creates an inifite redirection loop.
Does anybody have an idea how to solve this?
From the Symfony documentation:
For each incoming request, Symfony checks each access_control entry to find one that matches the current request. As soon as it finds a matching access_control entry, it stops - only the first matching access_control is used to enforce access.
When you set access_control in your security config, you want to put your least-restrictive matches last. In your case you will always match on the first pattern since all routes match on ^/ and therefore do not require any authentication. Change your access_control to this:
access_control:
- { path: ^/backend_login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/backend, roles: ROLE_ADMIN }
- { path: ^/user/fetch, roles: ROLE_USER }
- { path: ^/level, roles: ROLE_USER }
- { path: ^/gallery, roles: ROLE_USER }
- { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY }
I removed the host parameter as it didn't seem relevant.
I used the basic login form in symfony2 and it works well ( without FOSUSERBUNDLE ).
But how to restrict acces if a user is already authenticated ?
if ($this->get('security.context')->isGranted('ROLE_ADMIN')) { }
the code above does not work because the login route is not under the firewall... and throw :
The security context contains no authentication token. One possible reason may be that there is no firewall configured for this URL.
How to solve it ?
As said, the login url must be under firewall if you want to have access to the token/authenticated user. This is possible allowing anonymous access and proper access control rules.
firewalls:
main:
pattern: ^/
# firewall settings
anonymous: true
access_control:
- { path: ^/$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, role: ROLE_USER }
You need to use firewall
Example of firewall:
firewalls:
main:
pattern: ^/
form_login:
check_path: /
login_path: /
always_use_default_target_path: true
default_target_path: /main
logout:
path: /logout
target : /
anonymous: true
security: true
access_control:
- { path: ^/main, roles: ["ROLE_USER","ROLE_ADMIN"] }
- { path: ^/admin, roles: ["ROLE_ADMIN"] }
http://symfony.com/doc/current/components/security/firewall.html