Symfony 2.8 - How to configure a firewall for any URL? - php

Whenever I deliberately - trying to custom error pages - try to access an undefined route, the server responds by a 500 error. Logs say :
request.CRITICAL: Exception thrown when handling an exception (Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException: The token storage contains no authentication token. One possible reason may be that there is no firewall configured for this URL.
This exception is thrown after the NotFoundException, hence the 500 error.
Thus, I tried to figure out how to configure a firewall for any URL, and more particularly for all of those who are already handled by a firewall, so that the credentials can actually be found. I came up to this UserBundle/Resources/config/security.yml :
security:
encoders:
FOS\UserBundle\Model\UserInterface: sha512
providers:
fos_userbundle:
id: fos_user.user_provider.username
firewalls:
dev:
pattern: ^/(_(profiler|wdt))/
security: false
public:
pattern: ^/(contact/faq)$
anonymous: true
secure:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_token_generator: security.csrf.token_manager
login_path: fos_user_security_login
check_path: fos_user_security_check
use_forward: false
failure_path: null
default_target_path: /
remember_me: true
logout:
path: fos_user_security_logout
target: /
anonymous: true
remember_me:
secret: %secret%
name: whatev
lifetime: 31536000
path: /
remember_me_parameter: _remember_me
secure: true
always_remember_me: true
default:
anonymous: true
Everything's imported in my main security file, which consists of :
imports:
- { resource: "#UserBundle/Resources/config/security.yml" }
security:
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_ADMIN
access_control:
- { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY } # my try to match all routes...
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/administration/, role: ROLE_ADMIN }
- { path: ^/user$, role: IS_AUTHENTICATED_FULLY }
Here is my error.html.twig under app/Resources/TwigBundle/views/Exception :
<!DOCTYPE html>
<html>
<head>
<meta charset="{{ _charset }}" />
<title>An Error Occurred: {{ status_text }}</title>
</head>
<body>
<h1>Oops! An Error Occurred</h1>
<h2>The server returned a "{{ status_code }} {{ status_text }}".</h2>
<div>
Something is broken. Please let us know what you were doing when this error occurred.
We will fix it as soon as possible. Sorry for any inconvenience caused.
</div>
</body>
</html>
Any clue on how to proceed?
Thanks a lot.

As pointed out by Federico, the issue comes from an event listener that was trying to execute :
public function add(Request $request)
{
if($this->securityContext->isGranted('IS_AUTHENTICATED_FULLY')) {
/* do stuff considering the user is logged in.
** This is wrong ; we can end up here while having a logged out user.
*/
Of course, when thinking twice about it, it seems dumb. Simply fix the whole problem by ensuring that you can indeed call isGranted() on the security context. To check this, you have to verify that :
the security context's token isn't null ;
this token's user is an instance of your User entity (the user is actually logged in).
This changes the above method to :
public function add(Request $request)
{
if($this->securityContext->getToken() === null)
return false;
if(!$this->securityContext->getToken()->getUser() instanceof User)
return false;
if($this->securityContext->isGranted('IS_AUTHENTICATED_FULLY')) {
// do stuff considering the user is logged in.

Related

Symfony 4 - two firewalls cause ERR_TOO_MANY_REDIRECTS

I am writing this because previous answers to Using multiple firewalls cause ERR_TOO_MANY_REDIRECTS in Symfony 2 have not been helpful. "Main" firewall seem to work just fine, "Admin" is the one causing problems. Every time I try to enter the path "http://localhost:8000/admin" it redirects to"http://localhost:8000/admin_login" as it should, but goes into redirect loop and crashes with the error named above.
security.yaml
security:
encoders:
App\Entity\User:
algorithm: bcrypt
Symfony\Component\Security\Core\User\User: plaintext
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_ADMIN
providers:
chain_provider:
chain:
providers: [in_memory, db_provider]
in_memory:
memory:
users:
theadmin:
password: iamadmin
roles: 'ROLE_SUPER_ADMIN'
db_provider:
entity:
class: App\Entity\User
property: email
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
admin:
pattern: /admin
anonymous: ~
form_login:
username_parameter: _username
login_path: /admin_login
check_path: /admin_login
provider: in_memory
default_target_path: admin
logout:
path: /admin_logout
target: /
main:
pattern: /
anonymous: ~
form_login:
username_parameter: _email
login_path: /login
check_path: /login
provider: db_provider
default_target_path: welcome
logout:
path: /logout
target: /
access_control:
- { path: ^/welcome, roles: ROLE_USER }
- { path: ^/admin, roles: ROLE_SUPER_ADMIN }
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin_login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
AdminSecurityController.php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
class AdminSecurityController extends AbstractController
{
/**
* #Route("/admin_login", name="admin_login")
*/
public function admin_login(Request $request, AuthenticationUtils $utils)
{
$error = $utils->getLastAuthenticationError();
$auth_checker = $this->get('security.authorization_checker');
if ($auth_checker->isGranted('ROLE_SUPER_ADMIN')) {
return $this->render('admin/dashboard.html.twig', [
'controller_name' => 'AdminController',
]);
} else{
return $this->render('admin_security/admin_login.html.twig', [
'error' => $error
]);
}
}
/**
* #Route("/admin_logout", name="admin_logout")
*/
public function admin_logout()
{
}
}
Access control entries are analyzed from the top to the bottom. So, you need to place the ^/admin_login entry before the ^/admin.
Imagine how the security component is currently set:
You visit the login form then press submit
You (guest) are redirected to the /admin_login path
Security component goes through the entries and matches the /admin_login to the ^/admin entry
Because it requires ROLE_SUPER_ADMIN, you thus end up with a loop
Remember to clear the cache afterwards.

Redirect anonymous user to /login page

So, I'm using FOSUserBundle and symfony 2.8 project
if there is any way to redirect anonymous user to /login page, if he required / page?
Use a firewall to protect /:
# app/config/security.yml
security:
firewalls:
app:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_token_generator: security.csrf.token_manager
logout: true
anonymous: true
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, role: ROLE_ADMIN }
More details in the FOSUserBundle docs.
First, check if the user is authorized. Then, use an if condition to redirect the user.
Full example of your index:
public function indexAction()
{
$context = $this->container->get('security.authorization_checker');
if (!($context->isGranted('IS_AUTHENTICATED_REMEMBERED'))) {
$this->redirect('http://yourpage.com/login');
} else {
//Do your other stuff here
}
}

always_use_default_target_path doesn't work when set on false

I have installed fos user bundle in Symfony 2.7.
Everything works fine but I have problem with redirecting. It allways redirect me to home: localhost/xxx/app_dev.php/. My security.yml
#security.yml
security:
encoders:
FOS\UserBundle\Model\UserInterface: bcrypt
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
always_use_default_target_path: false
default_target_path: /
target_path_parameter: _target_path
use_referer: false
logout: true
anonymous: true
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/, role: ROLE_ADMIN }
What problem can live?
Check your login form, what input fields is it contain?
In the configuration you added:
target_path_parameter: _target_path
This will use the _target_path hidden input field in your login form to determine where to redirect the user after login. (I suppose this is an empty string or defaults to the /)
Uncomment this line and give it a try.
Regards to Andras Laczi answer I added made my own flexible solution (probably better one exist)
Step ONE: I added to security.yml following line:
firewalls:
main:
form_login:
...
failure_path_parameter: _failure_path
Step TWO: In twig, in places where I want to generate redirecting to login i added
Log in
Step THREE: Overriding FOSUserBundle SecurityController, and adding following lines somewhere in LoginAction
$targetPath = $request->query->get('targetPath', 'app_index');
$failurePath = $targetPath;
Step FOUR: Overriding FOSUserBundle Login Form adding following hidden fields:
<input type="hidden" name="_target_path" value="{{ targetPath }}" />
<input type="hidden" name="_failure_path" value="/login?targetPath={{ failurePath }}" />

Securized the login system in symfony 3

I have a problem with my system login in symfony 3. So my security.yml is:
security:
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_FMTI: ROLE_FMTI
ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
secured_area:
pattern: ^/admin
anonymous: ~
form_login:
always_use_default_target_path: true
default_target_path: /admin/homepage
login_path: /admin/login
check_path: /admin/login_check
logout:
path: /admin/logout
invalidate_session: true
target: /admin/login
access_control:
- { path: ^/admin/homepage, roles: ROLE_ADMIN }
providers:
in_memory:
memory:
users:
admin: { password: admin, roles: 'ROLE_ADMIN' }
encoders:
Symfony\Component\Security\Core\User\User: plaintext
The routing :
app_admin_homepage:
path: /homepage
defaults: { _controller: AppAdminBundle:Login:index }
login:
path: /login
defaults: { _controller: AppAdminBundle:Login:login }
login_check:
path: /login_check
logout:
path: /logout
And the method login from LoginController :
public function loginAction(Request $request)
{
$authenticationUtils = $this->get('security.authentication_utils');
// get the login error if there is one
$error = $authenticationUtils->getLastAuthenticationError();
// last username entered by the user
$lastUsername = $authenticationUtils->getLastUsername();
return $this->render('AppAdminBundle:Member:login.html.twig', array(
'last_username' => $lastUsername,
'error' => $error,
));
}
The problem is that if, I'm login in the application with credentials : admin/admin. After that I do the logout.
If I tried to access test.dev/admin/homepage ----> I'm redirecting vers login page witch is test.dev/admin/login, so it's good, I'm login as admin.
If I tried to access test.dev/admin/news/all -----> I can access this page without do the login, and I'm login as anonymous
So I want to redirect to login page for all routes /admin/* if user is not authentificated. Thx and sorry for my english
In the access Control you need to add this :
access_control:
- { path: ^/admin/, roles: ROLE_ADMIN }
Which means that for anything beyond the /admin/ route the ROLE_ADMIN is required.
-- update
If you need to access to /admin/login/ you need to add to every admin route except the /login, a path pattern like /admin/api/, so in your access control you gonna have this :
access_control:
- { path: ^/admin/api/, roles: ROLE_ADMIN }

Symfony2 Logout code placement, where do I put the invalidate code

New Symfony user here...
The examples in the Symfony Documentation don't actually have any examples of how to do a proper logout. Here is my security.yml
security:
encoders:
Symfony\Component\Security\Core\User\User: plaintext
AppBundle\Entity\User: bcrypt
role_hierarchy:
ROLE_ADMIN: [ROLE_USER]
providers:
chain_provider:
chain:
providers: [in_memory, user_db]
in_memory:
memory:
users:
admin: { password: adminpass, roles: ROLE_ADMIN }
user_db:
entity: { class: AppBundle:User, property: username }
firewalls:
main:
pattern: /.*
form_login:
login_path: /login
check_path: /login_check
default_target_path: /
logout:
path: /logout
target: /
invalidate_session: true
delete_cookies:
name:
path: null
domain: null
security: true
anonymous: true
access_control:
- { path: /login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: /cms/user, roles: ROLE_ADMIN }
- { path: /.*, roles: IS_AUTHENTICATED_ANONYMOUSLY }
I was under the impression with those settings that simply hitting the /logout route the session would be destroyed and the user would be redirected to the login page. However in trying to do this, I get a no route found error.
I found this code here on stack-overflow...
$this->get('security.token_storage')->setToken(null);
$this->get('request')->getSession()->invalidate();
Great, but I'm so new in Symfony that I don't know where to put it. All of the examples here on Stack give that code, but don't say how to implement it. Do I write a logout action like this?
/**
* #Route("/logout")
*/
public function logoutAction() {
$this->get('security.token_storage')->setToken(null);
$this->get('request')->getSession()->invalidate();
//if this works how do I redirect to another route,
//specifically back to /login
return $this->render(
//do i need a template?
//do i need the array here?
);
}
No needed to write logout action in controller. All you have to do, is add the route with logout path.
In app/config/routing.yml:
user_logout:
path: /logout

Categories