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
Related
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
I am trying to implement token authentication (in addition to form login) by following these articles:
https://symfony.com/doc/current/security/api_key_authentication.html
https://symfony.com/doc/current/security/multiple_user_providers.html
Here is my security.yaml:
main:
anonymous: true
pattern: ^/
provider: db_provider
form_login:
login_path: auth_login
check_path: auth_login
#secured_area:
logout:
path: /auth/logout
target: /
token:
anonymous: true
pattern: ^/token
stateless: false
simple_preauth:
authenticator: App\Security\TokenAuthenticator
provider: token_user_provider
This doesn't work - the token authenticators never get called unless I comment out the "main" firewall.
I think I can achieve my requirement by following this article and using just "main" firewall:
https://symfony.com/doc/current/security/multiple_user_providers.html
However I would prefer the approach I am attempting right now because I don't want the token authenticator to fire on every single request I want it limited to just /token paths and I would rather avoid checking for the paths inside the TokenAuthenticator::createToken(...) as suggested in the docs:
https://symfony.com/doc/current/security/api_key_authentication.html#only-authenticating-for-certain-urls
Any ideas, suggestions?
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.
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.
I have implemented a custom authentication provider successfully, but now I also need to add 'remember me' functionality, and I couldn't find docs on how to do that.
I tried adding this:
remember_me:
key: "%secret%"
lifetime: 31536000 # 1 year
always_remember_me: true
But it says this:
You must configure at least one remember-me aware listener (such as form-login) for each firewall that has remember-me enabled.
I found this but I'm not sure how to use it: Symfony\Component\Security\Core\Authentication\Provider\RememberMeAuthenticationProvider
So where is the RememberMeAwareInterface? (I guess there is one? Like ContainerAware) And what should I do with it?
I don't think I need to write my own implementation, the default one should work fine with my custom auth provider.
I was having the same issue with a custom Facebook authentication provider I wrote. The solution ended up being pretty simple:
I'll assume you implemented a custom authentication provider with a custom SecurityFactoryInterface implementation that extends from Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\AbstractFactory. If you did this, the rest is a matter of configuration:
In your security configuration, configure the remember_me functionality for your firewall. Assuming you're configuring that into the public firewall, the added config params might look something like this:
firewalls:
public:
remember_me:
key: "%secret%"
lifetime: 31536000 # 365 days in seconds
path: /
domain: ~ # Defaults to the current domain from $_SERVER
In the same configuration, enable the remember_me functionality for your authentication provider. Assuming you're configuring that into the public firewall and your SecurityFactoryInterface implementation's getKey() method returns yourAuthProviderKey, the added config params might look something like this:
firewalls:
public:
yourAuthProviderKey:
remember_me: true
Finally, when your Authentication Provider handles logins, make sure you request the remember me feature by having an http GET or POST parameter named _remember_me with value 1 in the http request. (Note though: this parameter might need a different name if you changed its default value in your security config.) For example, in my case, I had to tell Facebook to redirect to the following URL after it handled the authentication: http://www.mydomain.com/auth-callback/?_remember_me=1. (Note the part after the ?)
Hope this helps!
Did you add this to your form_login section?
form_login:
remember_me: true
From Symfony 2.8, the "key" is replaced by "secret". So you will have:
remember_me:
secret: %secret%
lifetime: 31536000
If you run across this error, that is the fix
You can try this:
firewalls:
secured_area:
pattern: ^/
anonymous: ~
form_login:
csrf_provider: form.csrf_provider
login_path: login
check_path: login_check
always_use_default_target_path: true
default_target_path: /the-cao
remember_me: true
logout:
path: /logout
target: /
remember_me:
key: "%secret%"
lifetime: 31536000 # 365 days in seconds
path: /
domain: ~ # Defaults to the current domain from $_SERVER
In my case it happened when i create a Factory class implementing SecurityFactoryInterface (as it was described in example "How to Create a custom Authentication Provider"). Later i found that another way to create this Factory is extending from AbstractFactory which contains neccessary readme stuff (you can find it create() method). So there are two solutions: 1) extend AbstractFactory instead of implementing SecurityFactoryInterface 2) implement SecurityFactoryInterface and copypaste readme related code. In symfony 3.1:
// add remember-me aware tag if requested
if ($this->isRememberMeAware($config)) {
$container
->getDefinition($listenerId)
->addTag('security.remember_me_aware', array('id' => $id, 'provider' => $userProviderId))
;
}