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.
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 have multiple proivders users and admin so i have following security.yml
security:
encoders:
AppBundle\Entity\AdminUser: bcrypt
# https://symfony.com/doc/current/security.html#b-configuring-how-users-are-loaded
providers:
#in_memory:
# memory: ~
admin_db:
entity: { class: AppBundle\Entity\AdminUser, property: email }
firewalls:
# disables authentication for assets and the profiler, adapt it according to your needs
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
admin_db:
provider: admin_db
anonymous: false
form_login:
login_path: login
check_path: login
# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#a-configuring-how-your-users-will-authenticate
#http_basic: ~
# https://symfony.com/doc/current/security/form_login_setup.html
#form_login: ~
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, roles: ROLE_ADMIN }
But when i try to access login page then i see this error
This page isn’t working localhost redirected you too many times. Try
clearing your cookies. ERR_TOO_MANY_REDIRECTS
The problem is that your firewall does not allow any anonymous access as specified with anonymous: false. That means your access control for login does not work. The 2 common ways to solve this are either taking the login rout out of the firewall or allowing anonymous access and then use access_controls to require a role.
If you want to move the login route out:
firewalls:
login:
pattern: ^/login$
security: false
admin_db:
...
form_login:
login_path: login
check_path: login_check
It's important that the route login_check points to something inside your firewall. So basically anything but /login will work, e.g. login/check. In your controller you can create an empty action for this or you can point it to the same action as login.
The other solution would be even simpler in your case, as your access_control is already correct:
firewalls:
admin_db:
...
anonymous: ~
In your access control you allow anonymous access for login, but all other routes must have ROLE_ADMIN. So no other changes should be necessary.
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.
In an application I am developing, I'm having a weird issue with the access control for the security component.
I use the FOSUserBundle (of course) for users and I copied the example access control rules from the bundle documentation to my security.yml The login screen (/login) works perfectly but the issue is, all other access control rules have absolutely no effect whatsoever. When a user goes to /register for example, he is redirected to /login, the same goes for /resetting.
This is my security.yml file:
jms_security_extra:
secure_all_services: false
expressions: true
security:
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_email
firewalls:
dev:
pattern: ^/(\_(profiler|wdt)|css|images|js)/
security: false
api:
pattern: ^/api
anonymous: false
form_login: false
provider: fos_userbundle
http_basic:
realm: "REST Service Realm"
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_provider: form.csrf_provider
logout: true
anonymous: ~
switch_user: { role: ROLE_SUPER_ADMIN, parameter: _impersonate }
access_control:
- { path: ^/login, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/superadmin/, role: ROLE_SUPER_ADMIN }
I have tried to turn of security for paths containing /resetting and /register, but that clearly won't work since the security token still needs to be available for the FOSUserBundle controllers.
Any help would be much appreciated!
It might be to do with the order of the access_control, try putting superadmin above the others. You also don't seem to have a secured_area section (like this example from Symfony2 access control redirects to login)
security:
firewalls:
secured_area:
pattern: ^/
anonymous: ~
form_login:
login_path: login
check_path: login_check
The problem was that another bundle was messing with each request checking if the user was logged in or not. If the user wasn't logged in, a redirect response was generated to the login page.
No idea why this was done, I think it comes from an era where the original authors had less experience with Symfony.
But so it proves again, always check the logs. Very thoroughly.
I'm new to Symfony2 and I'm trying to create a basic registration + login system. So, with the help of the Symfony2 documentation I created this security.yml:
security:
encoders:
TestCompany\InternetBundle\Entity\Member:
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: TestCompanyInternetBundle:Member, property: username }
firewalls:
admin_area:
pattern: ^/admin
anonymous: ~
form_login:
login_path: /login
check_path: /login_check
access_control:
- { path: ^/admin, roles: ROLE_ADMIN }
and I used this routing for it:
login_check:
pattern: /login_check
login:
pattern: /login
defaults: { _controller: TestCompanyInternetBundle:Admin:login }
According to http://symfony.com/doc/current/book/security.html#using-a-traditional-login-form I do NOT need to implement a controller for the login_check route. Yet, Symfony returns this error to me:
Unable to find the controller for path "/login_check". Maybe you forgot to add the matching route in your routing configuration?
Do you see anything I could have done wrong here? The login page is almost an exact copy of the one used in the documentation. The error occurs on the page: http://localhost/SymfonyTest/web/app_dev.php/login_check, which is the page I get sent to after using the login form.
http://symfony.com/doc/current/book/security.html#using-a-traditional-login-form
Be sure /login_check is behind a firewall.
Therefore, in your example, you have specified a prefix of /admin for your secured area, therefore your login check route should also have that prefix e.g. /admin/login_check
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.
Example security.yml configuration:
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
secured_area:
pattern: ^/
form_login:
login_path: /login
check_path: /login_check
logout:
path: /demo/secured/logout
target: /demo/
anonymous: ~
....
access_control:
- { path: ^/admin, roles: ROLE_ADMIN }
I would recomend that you use the FOSUserBundle as this seems the quickest way to do what you would like to do: FOSUserBundle
Installation is very straight-forward and would allow you to get your app working in a very short amount of time. Good luck!
EDIT:
Could you post your controller TestCompanyInternetBundle:Admin:login? Does you controller extend the security controller at all?
You should also include your security.yml. Make sure you have:
firewalls:
login_firewall:
pattern: ^/login$
anonymous: ~
in your security.yml. This is a common pitfall.