How is it possible to get app.user from unsecure area?
So I have secured area which starts from ^/user.
But I need to display logout form on area which is accessible for everyone and not secured. How is this possible? My security.yml:
security:
encoders:
Symfony\Component\Security\Core\User\User: plaintext
###:
algorithm: sha512
encode-as-base64: true
iterations: 10
###:
algorithm: sha512
encode-as-base64: true
iterations: 10
role_hierarchy:
providers:
admin:
name: admin
entity: { class: ###, property: login }
user:
name: user
entity: { class: ###, property: login }
firewalls:
admin:
pattern: ^/admin
form_login:
login_path: ###_login
check_path: ###_login_process
default_target_path: /admin/dashboard
anonymous: ~
logout:
path: /admin/logout
target: /admin/login
provider: admin
remember_me:
key: "###"
lifetime: 604800
path: /
domain: ~
user:
pattern: ^/user
form_login:
login_path: ###_login
check_path: ###_login_process
default_target_path: ###
anonymous: ~
logout:
path: /user/logout
target: /user/login
provider: user
remember_me:
key: "###"
lifetime: 604800
path: /
domain: ~
access_control:
- { path: ^/admin/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/, roles: ROLE_ADMIN }
- { path: ^/user/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/user/, roles: ROLE_USER }
Well I changed a little bit my security.yml. So currently everything works ok.
user:
pattern: ^/
access_control:
- { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY }
...
UPDATE 1
It seems that line in access_controll is not required. Moreover by some reason(might be cache) anonymoous users were accessing /user areas
You can get app.user in some unsecured area because Symfony security relies on 2 different mechanisms: authentication and authorization.
Authentication is defined by firewalls. As soon as you get under a firewall, you get a token and eventually a app.user, even if it is anonymous.
Authorization is related to access_control rules. It is a second step, you can't put access control rules outside of a firewall. There you will deal with the ROLE requirement, in example if ROLE_ANONYMOUS is enoug, if you want ROLE_USER...
One more thing: to complexify a little further, a firewall can allow or disallow anonymous users. By default it is true, as it is required to have you login and login_check paths under yoru firewall though you cant' require there users to have a role other than ROLE_ANONYMOUS (if you do so, you will have an infinite loop).
Related
My application is separated in three parts:
administration: ^/backend protected by ip
secured area: ^/member protected by login
public routes: ^/
Everything works fine except the access_denied_url. I tried specifying a route name as well as a plain path.
When I access /backend from an ip other than the configured one I get the following message:
Full authentication is required to access this resource.
500 Internal Server Error - InsufficientAuthenticationException
1 linked Exception: AccessDeniedException ยป
In dev environment this exception isn't catched at all leading to a fatal error but shouldn't the access_denied_url option somehow redirect to the given url anyway?
This is my security.yml:
security:
firewalls:
backend:
pattern: ^/backend
anonymous: ~
access_denied_url: /403
main:
pattern: ^/
anonymous: ~
form_login:
success_handler: my_auth_handler
failure_handler: my_auth_handler
use_referer: true
check_path: login_check
logout:
path: /logout
success_handler: my_auth_handler
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
access_control:
- { path: ^/backend, roles: IS_AUTHENTICATED_ANONYMOUSLY, ips: [127.0.0.1] }
- { path: ^/backend, roles: ROLE_NO_ACCESS }
- { path: ^/userlounge, roles: IS_AUTHENTICATED_FULLY }
- { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY }
providers:
frontend:
id: my_user_provider
encoders:
My\FrontEndBundle\User\MyUser:
algorithm: md5
encode_as_base64: false
iterations: 1
Thanks in advance for any help!
access_denied_url only works when the user's token is not anonymous and rememberme.
For more detail, see:
https://github.com/symfony/symfony/blob/2.6/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php#L120
https://github.com/symfony/symfony/blob/2.6/src/Symfony/Component/Security/Core/Authentication/AuthenticationTrustResolver.php#L65
I think you should try to specify the option access_denied_url on the security node not on the specific firewall (backend) because I think it might be the other firewall throwing the AccessDenied Exception.
Source: http://symfony.com/doc/current/reference/configuration/security.html
Alternatively you can create an AcccessDeniedListener, see this page for a tutorial: http://www.insanevisions.com/articles/view/symfony-2-access-denied-listener
I am trying to set up user and security management in a first test application of mine and I have come to be a bit lost as to what does what.
My setup thus far: Symfony 2.5, SonataUserBundle (and with it FOSUserBundle)
In my app/config/config.yml, I have the following settings that I make out to be relevant in terms of managing site security (most taken over from the setup instructions of the various bundles I included):
imports:
- { resource: security.yml }
[...]
fos_user:
firewall_name: main
[...]
security:
# FOSUserBundle config
# cf. https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/Resources/doc/index.md#step-4-configure-your-applications-securityyml
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
firewalls:
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_provider: form.csrf_provider
logout: true
anonymous: true
# end of FOSUserBundle config
access_control:
# URL of FOSUserBundle which need to be available to anonymous users
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
# Admin login page needs to be access without credential
- { path: ^/admin/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/logout$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/login_check$, role: IS_AUTHENTICATED_ANONYMOUSLY }
# Secured part of the site
# This config requires being logged for the whole site and having the admin role for the admin part.
# Change these rules to adapt them to your needs
- { path: ^/admin/, role: [ROLE_ADMIN, ROLE_SONATA_ADMIN] }
- { path: ^/.*, role: IS_AUTHENTICATED_ANONYMOUSLY }
My app/config/security.yml looks as follows:
security:
# added with Sonata User Bundle
encoders:
FOS\UserBundle\Model\UserInterface: sha512
# end
providers:
in_memory:
memory: ~
# added with Sonata User Bundle
fos_userbundle:
id: fos_user.user_manager
# end
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
# added with Sonata User Bundle
# -> custom firewall for the admin area of the URL
admin:
pattern: /admin(.*)
context: user
form_login:
provider: fos_userbundle
login_path: /admin/login
use_forward: false
check_path: /admin/login_check
failure_path: null
logout:
path: /admin/logout
anonymous: true
# -> end custom configuration
# default login area for standard users
# This firewall is used to handle the public login area
# This part is handled by the FOS User Bundle
main:
pattern: /(.*)
context: user
form_login:
provider: fos_userbundle
login_path: /login
use_forward: false
check_path: /login_check
failure_path: null
logout: true
anonymous: true
# end
default:
anonymous: ~
# Sonata
acl:
connection: default
role_hierarchy:
ROLE_ADMIN: [ROLE_USER, ROLE_SONATA_ADMIN]
ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
SONATA:
- ROLE_SONATA_PAGE_ADMIN_PAGE_EDIT # if you are using acl then this line must be commented
Here are my questions:
Precedence of configurations
Based on my understanding of the "patterns" of Symfony thus far, anything in security.yml is loaded first and would thus take precedence over any new definitions for identical parameters further down in my config.yml. Is that correct?
Duplicate definitions
It seems to me that the following are defined twice, once in security.yml, once in config.yml:
The provider for FOSUserBundle (different values, fos_user.user_manager and fos_user.user_provider.username)
The encoder for FOS\UserBundle\Model\UserInterface
The pattern for the main firewall (^/vs. .*)
Are these indeed defining the same? Is it safe to assume that in all these cases, only those settings defined in security.yml apply?
Best practices
How should security-related definitions generally be divided between security.yml and config.yml (and other potential locations)?
As Cerad mentionned in a comment, you have the same section security: in both files.
Look at the start of the app/config/config.yml file:
imports:
- { resource: security.yml }
This means that the security.yml file will be imported when the config.yml file will be parsed by Symfony2. So you can keep only the security: section in the app/config/security.yml file in order to define the security configuration.
This is the default configuration, see these files in the official GitHub repository:
app/config/config.yml (no security: section)
app/config/security.yml (contains a security: section)
Question: I want to create an admin part in my Symfony2 website that would be available only to users with a ROLE_ADMIN
I don't know if I should create a new firewall or use acces controls. I tried to do both together but the admin part is still accessible to all users.
Currently all the website is under secured area firewall and pages i want available to anonymous are freed with access control.
Here is my security.yml
security:
encoders:
Symfony\Component\Security\Core\User\User: plaintext
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_email
my_facebook_provider:
id: my_user.facebook_provider
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login:
pattern: ^/login$
security: false
context: login
admin:
pattern: /admin/
form_login:
provider: fos_userbundle
check_path: /login_check
login_path: /login
anonymous: ~
secured_area:
pattern: ^/
anonymous: ~
form_login:
login_path: /login
check_path: /login_check
default_target_path: tk_group_homepage
provider: fos_userbundle
remember_me: true
csrf_provider: form.csrf_provider
remember_me:
key: %secret%
lifetime: 31536000 # 365 days in seconds
fos_facebook:
app_url: "%api_facebook_name%"
server_url: "%api_facebook_server%"
check_path: /login_facebook_check
default_target_path: tk_user_homepage
provider: my_facebook_provider
logout:
path: fos_user_security_logout
target: fos_user_security_login
invalidate_session: false
context: login
access_control:
- { path: ^/$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/new, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/invitation, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/(subscribe|about|blog|press|contact), role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, role: IS_AUTHENTICATED_REMEMBERED }
- { path: ^/admin/, role: ROLE_ADMIN }
I am also thinking about checking in the controller is the user has an admin role and throwing an exception if not, as my admin part is only one page currently. But I do not know if it is best practice and it could be a problem if i want to extend my admin part.
And I do not want to create a new user provider as we would be only 2 admins.
Thank you very much,
Jules
You should remove the admin firewall and rely on access_control; If you have admin login form under the /admin/ URL, you of course will not be able to see it before logging in, so you should either use the /login form to sign in as admin, or modify your access_control:
- { path: ^/admin/login/, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/, role: ROLE_ADMIN }
here is what official doc says about your situation:
Multiple firewalls don't share security context If you're using multiple firewalls and you authenticate against one firewall, you will
not be authenticated against any other firewalls automatically.
Different firewalls are like different security systems. To do this
you have to explicitly specify the same Firewall Context for different
firewalls. But usually for most applications, having one main firewall
is enough.
http://symfony.com/doc/current/book/security.html#book-security-common-pitfalls
You should read the whole Common pitfalls section
If you would really really like to use different firewalls, just do as the documentation states, and share the same firewall context beetween them. This is also described in the documentation:
http://symfony.com/doc/current/reference/configuration/security.html#reference-security-firewall-context
and here is a simple example:
admin:
(... other options ...)
context: my_security_context
secured_area:
context: my_security_context
(... other options ...)
The Access Control looks for the first match.
Because of that you need to put this line:
- { path: ^/admin/, role: ROLE_ADMIN }
Before this line:
- { path: ^/$, role: IS_AUTHENTICATED_ANONYMOUSLY }
If you do not, /admin/whatever matches the path ^/$ and needs no ROLE_ADMIN.
I'm trying to setup a login system using the Doctrine Entity Provider but I always get this error:
No encoder has been configured for account "Prefix\MainBundle\Entity\Admin"
Here is my setup:
security.yml
security:
encoders:
Prefix\MainBundle\Entity\Admin:
algorithm: sha1
encode_as_base64: false
iterations: 1
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH ]
providers:
administrators:
entity: { class: PrefixMainBundle:Admin, property: username }
firewalls:
administrators:
pattern: ^/admin/
anonymous: ~
provider: administrators
form_login:
login_path: /admin/login
check_path: /admin/login_check
access_control:
- { path: ^/admin/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin, roles: ROLE_ADMIN }
I have the Entity created and implements the UserInterface but I can't make it work, it'd great if someone could shed some light on this.
Move the provider to be under the form login:
form_login:
login_path: /admin/login
check_path: /admin/login_check
provider: administrators
I am assuming you the error when trying to login using a form.
And while not directly related, you should replace your login paths with named routes.
I'm trying to take advantage of Symfony's authentication and authorization capabilities however I'm somewhat confused as to what my security.yml file should look like.
I'm looking to accomplish the following objectives:
1) The routes / and /join (are avilable to everyeone - no login required).
2) all other routes require a login/password.
3) the /adimin route should be futher restricted to admin users only.
4) all users should be authenticated against the database.
I have item 4 figured out (I think) - see below. I'm not sure what the administrators: word means though. Does that mean only administrators use the User class? Should that say users: or something else?
security:
encoders:
MySite\Bundle\Entity\User:
algorithm: sha1
encode_as_base64: false
iterations: 1
providers:
administrators: (??? what doest his mean ???)
entity: { class: MySiteBundle:User }
More Importantly --
For Items 1, 2, and 3 I'm not sure what to put. I have a bunch of entries under the firewalls: section and the access_control: sections however It just doesnt work or make sense. Can someone post what the security.yml should look like just by the goals I'm looking to accomplish in numbers 1 - 3?
Here is a configuration exemple from what I understood from your needs:
security:
encoders:
"MySite\Bundle\Entity\User": { algorithm: sha1, encode_as_base64: false, iterations: 1 }
providers:
database: { entity: "MySite\Bundle\Entity\User" }
firewalls:
dev:
pattern: ^/(_profiler|_wdt|css|js)
security: false
main:
pattern: ^/
provider: database
anonymous: true
# the rest of your firewall's config
access_control:
- { path: ^/(join)?$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, roles: IS_AUTHENTICATED_FULLY }
We configure the password encoder for the user entity and we define a provider for it.
Then we define a dev firewall to deactivate security for the debug/profiler/asset pathes and a main one that will be the real firewall for the application. This last firewall will use the previously defined user provider and allow anomymous users (important!).
Finally in the access control map, we first define a rule for the pathes allowed to anonymous users and then a generic rule that requires the user to be fully authenticated for the rest of the site.
For anyone else asking this or a similiar question, I've managed to get this working using the following settings in security.yml.
security:
encoders:
MySite\Bundle\Entity\User:
algorithm: sha1
encode_as_base64: false
iterations: 1
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
database:
entity: { class: MySiteBundle:User }
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
prod:
pattern: ^/
provider: database
anonymous: true
form_login:
check_path: /login_check
login_path: /login
default_target_path: /home
always_use_default_target_path: true
logout:
path: /logout
target: /
access_control:
- { path: ^/admin, roles: ROLE_ADMIN }
- { path: ^/build, roles: ROLE_USER }
- { path: ^/join, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY }