Symfony 3.0.3 I want to exclude URLs starting with /document from having to log in
My current security.yml firewalls:
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
docs:
pattern: ^/document
security: false
main:
pattern: ^/
http_basic: ~
provider: our_db_provider
anonymous: ~
form_login:
login_path: /
check_path: login
logout:
path: /logout
target: /
invalidate_session: true
But this results in Error 500 : "The token storage contains no authentication token. One possible reason may be that there is no firewall configured for this URL." when visiting /document
How is your access_control configuration in security.yml. Shouldn't you allow /document for IS_AUTHENTICATED_ANONYMOUSLY?
access_control:
- { path: ^/document$, role: IS_AUTHENTICATED_ANONYMOUSLY }
In this case, you don't have to define a separate firewall for /document.
Related
I have a Symfony Application that has two primary sections. / (everything under root e.g. /userProfile) and /api/ (everything under the /api route e.g. /api/userInfo/3).
I'm using Twig to render the actual pages under root, and a simple JsonResponse to render everything under /api. Currently, when a user tries to access any page / resource when they are not logged in, they are redirected to /login and then to the page / resource they requested.
I'd like to alter this behavior for all resources under /api. What I'd like /api/whatever to do is either return the requested resource (if logged in), or return a 401 if not logged in. I'd like to continue to redirect to /login for all other routes.
(NOTE: the /api routes are not "RESTful" API routes per ce. They are "internal" API routes that the UI uses to request data it needs to render the various pages. So it's safe to assume that a user would have logged in via the normal login form prior to their client requesting one of these routes.)
Here's my security.yaml:
security:
providers:
db_provider:
id: database_user_provider
encoders:
App\Utility\Security\DatabaseUser: bcrypt
access_decision_manager:
strategy: unanimous
allow_if_all_abstain: false
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
pattern: ^/
context: main
form_login:
provider: db_provider
login_path: login
check_path: process_login
default_target_path: manage
use_referer: true
failure_handler: App\Utility\Security\AuthenticationFailureHandler
user_checker: App\Utility\Security\UserChecker
anonymous: ~
logout:
path: logout
target: login
access_denied_handler: App\Utility\Security\AccessDeniedHandler #Turn this off in dev.
# 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, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/forgot, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/%app.locales%, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, roles: ROLE_USER }
I've tried adding a new firewall context of api:
api:
pattern: ^/api
context: main
# If I don't include this (from "main" firewall), I get an error stating no UserAuthenticationListener has been provided for secuirty.firewall.api.
form_login:
provider: db_provider
login_path: login
check_path: process_login
use_referer: true
failure_handler: App\Utility\Security\AuthenticationFailureHandler
Symfony complains if I do not include login_path and check_path.
So, how do I tell Symfony to simply fail and return a 401 when a user is not logged in (or session has expired), when (and only when) they are accessing a route under /api?
Thanks.
To get this working, move the api firewall above main.
We can then set it up on security.yaml with the following structure:
api:
pattern: ^/api
context: main
stateless: false
anonymous: true
guard:
authenticators:
- App\Security\ApiAuthenticator
provider: db_provider
The other thing we need is an implementation of AuthenticatorInterface. e.g. the App\Security\ApiAuthenticator
We only need to implement the following two methods from the interface:
start and supports
public function start(Request $request, AuthenticationException $authException = null)
{
return new Response('', Response::HTTP_UNAUTHORIZED);
}
public function supports(Request $request)
{
return false;
}
Note: The above implementation was tested on Symfony 4 (4.3)
Add the path ^/api with the allowed roles in the access_control section https://symfony.com/doc/current/security.html#add-code-to-deny-access
This is how my security is looking. It's working the way you wanted, just that I use OAuth
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
oauth_token:
pattern: ^/oauth/v2/token
security: false
oauth_authorize:
pattern: ^/oauth/v2/auth
form_login:
provider: fos_userbundle
check_path: /oauth/v2/auth_login_check
login_path: /oauth/v2/auth_login
use_referer: true
api:
pattern: ^/api
fos_oauth: true
stateless: true
anonymous: false
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_token_generator: security.csrf.token_manager
logout: true
anonymous: true
guard:
provider: fos_userbundle
authenticators:
- App\Security\GoogleAuthenticator
- App\Security\FacebookAuthenticator
entry_point: App\Security\LoginFormAuthenticator
i would use the #Security annotaion
https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/security.html
I am running into an issue with setting up Authentication in Symfony 2.8 with Saml plugin (https://www.lightsaml.com/SP-Bundle/Getting-started/).
Problem:
I want to able to login via SAML and via going to admin page. The /admin/login page works fine, I see the user authenticated from the database. However, when I try to go through the Saml process, I always land on the /discovery page. When I see the logs, I do user is authenticated. So, I think I have something not correctly in security settings. Please let me know if you can help
Here are the settings from
config/security.yml file:
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login_firewall:
pattern: ^/saml/login$
anonymous: ~
discovery_firewall:
pattern: ^/saml/discovery$
anonymous: ~
secured_area:
pattern: ^/
anonymous: ~
light_saml_sp:
provider: db_provider # user provider name configured in step 9
#user_creator: user_creator # name of the user creator service created in step 10
login_path: /saml/login
check_path: /saml/login_check
default_target_path: /profile
form_login:
login_path: /admin/login
check_path: /admin/login_check
default_target_path: /
remember_me: true
logout:
path: /logout
target: /
# activate different ways to authenticate
# http_basic: ~
# http://symfony.com/doc/current/book/security.html#a-configuring-how-your-users-will-authenticate
# form_login: ~
# http://symfony.com/doc/current/cookbook/security/form_login_setup.html
access_control:
- { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/login$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/login$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/profile, roles: ROLE_USER }
I've been trying for a couple of days now ... and still can't make this work I've read the documentation page over an over, I'm going crazy and I can't understand what is wrong.
It's very important for me to know and learn the way Symfony works because my new job requires me to work with it.
So I went to the documentation page at : http://symfony.com/doc/current/cookbook/security/entity_provider.html#security-config-entity-provider
security.yml
encoders:
Paul\FrontBundle\Entity\User:
algorithm: bcrypt
# http://symfony.com/doc/current/book/security.html#where-do-users-come-from-user-providers
providers:
db_users:
entity:
class: Paul\FrontBundle\Entity\User
property: username
firewalls:
admin:
pattern: ^/admin
provider: db_users
form_login:
check_path: admin_login_check
login_path: admin_login
# disables authentication for assets and the profiler, adapt it according to your needs
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: ~
My user entity implements the UserInterface
What is wrong ?
Can anyone please explain me what I'm doing wrong ?
Thanks !
OK, so the problem was the security context, for those who are interested this link will explain more.
Now what I've done is the following:
In security.yml
firewalls:
# disables authentication for assets and the profiler, adapt it according to your needs
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
protected_area:
pattern: ^/protected
anonymous: ~
form_login:
login_path: login
check_path: login
default_target_path: /protected
provider: database_users
logout:
path: logout
target: /
success_handler: ~
invalidate_session: true
main:
anonymous: ~
access_control:
- { path: ^/protected/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/protected, roles: ROLE_USER }
In routing.yml
login:
path: /protected/login
defaults: { _controller: PaulDemoBundle:Security:login }
login_check:
path: /login_check
logout:
path: /protected/logout
So to explain it more, The login form is now in the context of protected_area firewall before /login , after /protected/login.
Also pay attention to the access_control node.
I hope this will help others.
I've implemented the SimpleSamlPhpBundle in order to authenticate a user on my Symfony application via SAML/Shibboleth.
I modified my security.yml file as follows:
security:
providers:
simplesaml:
id: saxid_user_provider
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
saml:
pattern: ^/
anonymous: true
stateless: true
simple_preauth:
authenticator: simplesamlphp.authenticator
provider: simplesaml
logout:
path: /logout
success_handler: simplesamlphp.logout_handler
access_control:
# Make imprint accessible for anonymous access
- { path: ^/imprint$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
As I have an imprint that I want to make accessible for anonymous users, I added the according line to the access_control section.
But this doesn't take effect, if I call example.com/imprint it redirects to the SimpleSAMLphp identity discovery page. Is my pattern wrong? I also tried without the trailing $ character, which didn't help.
I used the "Using a traditional login form" tutorial from symfony.com to authentificate my users. With a simple http auth it works great.
After the login was submitted I get this Exception:
Unable to find the controller for path "/login_check". Maybe you
forgot to add the matching route in your routing configuration?
Well, in the tutorial I read:
You will not need to implement a controller for the /login_check URL as the firewall will automatically catch and process any form submitted to this URL.
I defined the routes and set the firewall settings:
security.yml
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
backend:
pattern: ^/backend
anonymous: ~
form_login:
provider: entity
login_path: /login
check_path: /login_check
#use_forward: true
logout:
path: /logout
target: /
routing.yml
login:
pattern: /login
defaults: { _controller: VitaSecurityBundle:Default:login }
login_check:
pattern: /login_check
logout:
pattern: /logout
The problem you are having is described here:
See http://symfony.com/doc/current/book/security.html, section "Avoid Common Pitfalls"
Be sure /login_check is behind a firewall
Next, make sure that your check_path URL (e.g. /login_check) is behind the firewall you're using for your form login (in this example, the single firewall matches all URLs, including /login_check). If /login_check doesn't match any firewall, you'll receive a Unable to find the controller for path "/login_check" exception.
In this example, your pattern specifies a prefix of /backend for secured paths. To work, your login check should be behind this same firewall.
So, to match the pattern which you have specified in your firewall, put login_check on a url path like this: /backend/login_check
I found the solution to my problem
I added the /backend prefix to my paths, removed the 'anonymous: ~' line and commented out the ACL for backend.
security.yml
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login_firewall:
pattern: ^/backend/login$
anonymous: ~
backend:
pattern: ^/backend
form_login:
provider: entity
login_path: /backend/login
check_path: /backend/login_check
#use_forward: true
logout:
path: /backend/logout
target: /
access_control:
#- { path: ^/backend, roles: ROLE_USER }
routing.yml
login:
pattern: /backend/login
defaults: { _controller: VitaSecurityBundle:Default:login }
login_check:
pattern: /backend/login_check
logout:
pattern: /backend/logout
The problem also tends to happen when you have two firewall with the same pattern. For example:
....
backend:
pattern: ^/*
....
frontend:
pattern: ^/*
You must change one of the two as follows:
....
backend:
pattern: ^/(administrador|backend)/*
....
frontend:
pattern: ^/*
Here is a sample code I used in a real-life project:
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
secured_area:
pattern: ^/cmd
anonymous: ~
form_login:
check_path: /cmd/login_check
login_path: /cmd/login
remember_me:
always_remember_me: true
key: "%secret%"
path: /cmd
domain: ~ # Defaults to the current domain from $_SERVER
logout:
path: /cmd/logout
target: /
admin:
pattern: ^/admin
http_basic:
realm: "Administration"
free_area:
pattern: ^/
anonymous: ~
In my case, only the /cmd/ part is secured, the /admin/ part is also secured, but with HTTP security.
Maybe you should try:
security.yml
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
backend:
pattern: ^/backend
anonymous: ~
form_login:
provider: entity
login_path: /backend/login
check_path: /backend/login_check
#use_forward: true
logout:
path: /backend/logout
target: /
and as of routing.yml:
login:
pattern: /backend/login
defaults: { _controller: VitaSecurityBundle:Default:login }
login_check:
pattern: /backend/login_check
logout:
pattern: /backend/logout
I think your problem might come from the fact security is not activated in your / part (the pattern of your secured area is ^/backend)
This was not workging for me and I try something else :
firewalls:
dev:
pattern: ^/(_profiler|_wdt|css|js)
security: false
login:
pattern: ^/login$
security: false
secured_area:
pattern: /(admin/.*|login_check)
provider: in_memory
form_login:
check_path: /login_check
login_path: /login
default_target_path: /admin
always_use_default_target_path: true
logout:
path: /logout
target: /
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, roles: ROLE_ADMIN }
With the following explanation, simpler than the explanation from zabojad.
The important thing is to put the login_check route inside a firewall and to let the login outside. With a or pattern you can succeed.
Max