Symfony2 firewall security.yml - symfony

i am new to symfony so i need your help. I got a problem with my my security. yml. I tried to make a little application which stores some data in my database and shows them on my homepage. It works really fine but changing the route from routing.yml:
addlink:
path: /addlink
defaults: { _controller: ExerciseLinkBundle:Exercise:addLink }
to
addlink:
path: /secured_area/addlink
defaults: { _controller: ExerciseLinkBundle:Exercise:addLink }
causes a redirect to my login site. As you see below i obviously really dont know what i am doing in the security.yml. Please tell me how to redirect to my 'addlink' route. As I mentioned it works fine using the first route so the controller/template has to be ok.
login_firewall:
pattern: ^/secured_area/login$
anonymous: ~
exercise:
pattern: ^/secured_area
form_login:
csrf_provider: form.csrf_provider
login_path: /secured_area/login
check_path: /secured_area/login_check
always_use_default_target_path: true
default_target_path: /secured_area/addlink
logout:
path: /secured_area/logout
target: /
And Please dont tell me about FOSUserBundle meanwhile i'ld use this but this one has to be finished first :). So please help me out of there.

Your firewall in security.yml is configured to protect every URL that begins with ^/secured_area. That means that if someone tries to access a URL like http://yoursite.dev/secured_area/addlink, the firewall would intercept this and make sure that the user is authorized to view that page. The reason it redirects to your login is because a user must be authenticated before the firewall can determine if the user is authorized to view the page. Once you sign in with an authorized user, you will be redirected to the initial page (/secured_area/addlink). And it looks like you are securing the /login_check URL, which means you will never be able to login.
I think there is a less confusing way to create your firewall. Try something like this:
firewalls:
exercise:
pattern: ^/
form_login:
csrf_provider: form.csrf_provider
login_path: /login
check_path: /login_check ### there is not reason to secure this URL
always_use_default_target_path: true
default_target_path: /secured_area/addlink
logout:
path: /secured_area/logout
target: /
anonymous: true
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/secured_area, role: IS_AUTHENTICATED_REMEMBERED }
- { path: ^/, role: IS_AUTHENTICATED_ANONYMOUSLY }
This will have a similar effect, but is cleaner and easier to see what is happening. First, with this approach you can still have some public pages if you wish. Second, your 'login_check' doesn't require authentication (which I think is part of the main problem you are seeing). Finally, with this configuration your whole site will go through this firewall. That doesn't mean your whole site will be password protected, it just means that you can specify (in the access_control part of security.yml) exactly which pages are viewable by unauthenticated users and which are viewable by authenticated users.
For more information on protecting your site, read the Authorization section of the Symfony security docs It has lots of good information.

Related

Symfony - How to log a user on one sub domain (not all) dynamically

I have a site with multiple subdomains. I would like to log users that have certain rights to one of the sub domain only when he's already authenticated on the 'main' site. Let's say that my main domain is www.domain.com, i have sub1.domain.com, sub2.domain.com, sub3.domain.com.
When a user is authenticated on domain.com, i would like to be able to redirect him to sub2.domain.com without asking him to re-authenticate. But it should not be authenticate to sub1.domain.com or sub3.domain.com.
I have read about setting the cookie_domain in the config.xml but in this case the user will be logged for all subdomains.
Is that possible ?
Thanks !
Edit for more info
I'm working with Symfony 2.7 and i have tried both solution in the security.yml : one main shared firewall and one per sub domain (See below).
But i have not configured the session cookie_domain in config.yml to '.domain.com' as i don't want to log the user in all the subdomains.
firewalls:
main:
pattern: ^/
host: %main_domain%
form_login:
provider: fos_userbundle
csrf_provider: form.csrf_provider
logout:
path: /logout
target: /login
anonymous: true
context: main_context
sub1:
pattern: ^/
host: %sub1_domain%
form_login:
provider: fos_userbundle
csrf_provider: form.csrf_provider
logout:
path: /logout
target: /login
anonymous: true
context: main_context
sub2:
pattern: ^/
host: %sub2_domain%
....
It is possible in multiple ways. Since you log in in your main domain, you need some way to specify which user has access to which sub domain. Using different roles seems like a reasonable approach for this. So, for example a user who has access to subdomain1 will also have a role like ROLE_USER_SUB1.
With this set up, you can modify your security.yaml and use the access_control settings to restrict access to certain roles based on the domain, using additional matching options
security:
access_control:
...
- { path: ^/, roles: ROLE_USER_SUB1, host: sub1\..* }
- { path: ^/, roles: ROLE_USER_SUB2, host: sub2\..* }
You might have to tweak this to your needs and you also have to be careful to have the correct ordering of the routes, as the first matching rule will be used.
Another possible solution is to use a simple event listener that is triggered on each request at the kernel.request (be careful to check the priority, as you probably need to put your listener after the firewall listener) or kernel.controller event and then use the access decision manager or Symfony\Component\Security\Core\Security to check whether the user is (a) logged in and (b) has the correct role set, see https://symfony.com/doc/current/security/securing_services.html

Symfony4 Security - Url parameter after login and redirect

I have a little url problem when I login and is redirected to a previous page.
A _GET parameter appears with the current url and it goes like that : /admin/series?_url=%2Fadmin%2Fseries
The current URL (the one where the user is redirected after the automatic login) is dupplicate in a _url parameter anfd i don't really want/need that.
For Example, I'm on page /admin/series.
When I'm logged out I'm either redirected to /login, either redirected to some url to login automatically (if remember_me is active).
In both ways, When i'm redirected to previous URL, the url used internally in the check_login is added to the "final" url I'm redirected to.
So I'm redirected into /admin/series?_url=%2Fadmin%2Fseries
What I would like is NOT have this URL parameter ?_url=%2Fadmin%2Fseries in my final url.
I use Symfony4 with security package and FosUser (I don't think it's related to FosUser though)
EDIT :
Here is my config/packages/security.yaml
I hvae no custom listener on the login action or something similar that could interact with the default behaviour of Security component or FosUser (I have a registration controller but there is nothing inside for now).
security:
encoders:
FOS\UserBundle\Model\UserInterface:
algorithm: argon2i
memory_cost: 16384 # Amount in KiB. 16 MiB
time_cost: 2 # Number of iterations
threads: 4 # Number of parallel threads
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_ADMIN
providers:
fos_userbundle:
id: fos_user.user_provider.username_email
firewalls:
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_token_generator: security.csrf.token_manager
always_use_default_target_path: false
default_target_path: admin_profile_index
use_referer: true
logout: true
anonymous: true
remember_me:
secret: '%kernel.secret%'
lifetime: 864000
path: /
domain: ~
ps : If I'm not clear enough, say me I'll try to explain it better.

Symfony 3 firewall protected area confusion

I want to protect by the firewall and so by login / session an application area in Symfony 3:
security:
firewalls:
seller:
pattern: ^/somearea
form_login:
login_path: /somearea/login
check_path: /somearea/login
logout:
path: /somearea/logout
target: /
anonymous: false
access_control:
- { path: ^/somearea/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/somearea, role: IS_AUTHENTICATED_FULLY }
But when I want to go to the /somearea area then the app gets confused and will be "ERR_TOO_MANY_REDIRECTS" and if I will (what actually I dont want) have that login at not behind the area (eg. /some2login or whatever different) then says the login must be starting with /somearea.
How can I solve this? Thank you!
You are disallowing anonymous access by setting anonymous: false, that is why the access_control will not go into effect. The simplest solution is probably to just change that setting to anonymous: ~, since your fallback access control for ^/somearea will ensure that no anonymous user is allowed.
Another solution would be to have a separate firewall just for login:
security:
firewalls:
login:
pattern: ^/somearea/login$
security: false
seller:
pattern: ^/somearea
form_login:
login_path: /somearea/login
check_path: /somearea/login_check
...
The login form will fall into the first firewall which is unsecured and always accessible, but when submitting the form you will send a request to /somearea/login_check which does not match the first firewall, but the second one and therefore authentication is attempted for the secured seller-area.

PUT method for Symfony firewall form_login paths

I'm configuring the Symfony firewall to handle a login form. The trick is that the check route must use the PUT method, not POST.
This is the part of my firewall configuration that is related to my problem:
firewalls:
main:
pattern: ^/
anonymous: true
provider: customer
form_login:
login_path: api_user_login
check_path: api_user_login_connect
As you can see, I don't use paths but routes instead. Mainly because I need to specify the method for the check_path (PUT in my case)
Here is my api_user_login_connect route:
api_user_login_connect:
path: /users
defaults: { _controller: ApiBundle:Login:connect }
methods: [PUT]
Symfony issues an error when I try to access /users, saying that there is no route for /users (in GET I assume). So I understand that the firewall won't let me use the PUT method for the check_path route, or that it doesn't read the whole route from the configuration, but just the path that is defined in the route.
How can I tell Symfony firewall to check credentials using a PUT request?
We found the answer before I posted this question, here it is...
For the firewall to accept login check on methods other than GET, you must this option: post_only: false. It's true by default.
firewalls:
main:
pattern: ^/
anonymous: true
provider: customer
post_only: false

how to get all users connected to default user without going through login page?

I want to secure my API with FOSUserBundle (and avoid the use of FOSOAuthServerBundle due to lack of documentation with complete example).
To make my API secure, I just created firewalls as follows:
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
api_doc:
pattern: ^/api/doc
security: false
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_token_generator: security.csrf.token_manager
logout: true
anonymous: true
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/api, roles: [ IS_AUTHENTICATED_FULLY ] }
- { path: ^/admin/, roles: [ROLE_SUPER_ADMIN]}
This is great! But this requires that every one has to be connected before using the website so that I can display the list of ads, etc. ( Even GET queries needs a connected for security purpose)
To overcome, I am thinking about having all the users connected with a "default" user with limited privileges (just enough for simple querying without posting).
Is it possible to do so?
Thanks for your help.
PS: I did manage to get FOSUserBundle and FOSOAuthServerBundle working together. In fact, I was able to create a client and get an access token for it through command lines. But, I was not able to config the security.yml properly so that I get a login page that returns an access token.
Take a look at the symfony entry on How to Authenticate Users with API Keys. The entry has most of the code that you need and is well documented.
You do have to add a field for the API key in your fos_user table e.g.
ALTER TABLE fos_user ADD api_key VARCHAR(255) DEFAULT NULL;
You also need to correctly implement the ApiKeyUserProvider::getUsernameForApiKey to look up in your database for the user based on the given API key, something like this:
$repository = $this->manager->getRepository('Application\UserBundle\Entity\User');
$user = $repository->findOneBy(array('apiKey' => $apiKey));
return empty($user) ? $user : $user->getUsername();
I implemented this a few years ago, it was simple to follow and has worked great!

Resources