I have login page with login form. So if user is already logged I want redirect him from login page to another. Secured area is all pages with .*/secured.html and login page url is - login/page.html. When I am trying to $this->container->get('security.context'); I got error that there is no security token because current page is not under secured area. So If I want to use token (if exists) should I add all these pages to the secured area? In this way symfony2 will check every time if user is logged (and maybe will redirect to login page) but If I add
login:
pattern: ^/demo/secured/login$
security: false
auth token also will not exist.
So what is the way to use auth token at all application pages? Or all these pages should be added to secured area?
If you turn off the security you don't have a token. Your login page have to place behind the firewall. And no you don't have to
add all your single pages to your settings.
Here is an example:
firewalls:
main:
pattern: ^/
form_login:
login_path: /account/login
check_path: /account/login_check
logout:
path: /account/logout
anonymous: true
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
access_control:
- { path: ^/account/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/account/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/movie/, role: ROLE_USER }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/, role: ROLE_ADMIN }
As you can see I activated the security on all pages, but I'll allow to access anonymously.
With this access control: - { path: ^/movie/, role: ROLE_USER } I've full control which user can access the page,
which implies that the user is already logged in.
For a deeper look I can recommend the Documentation: http://symfony.com/doc/current/book/security.html
Cheers.
So If I want to use token (if exists) should I add all these pages to
the secured area?
Yes, you have to put those where you want to access security token behind firewall. If you want to also access security token in login page, you also have to put it in behind the same firewall. But then make the access control for it as IS_AUTHENTICATED_ANONYMOUSLY.
access_control:
- { path: ^/secured/login/page.html$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
Related
I'm using Symfony 4 and need users to be authenticated before accessing any page. These are my firewall-settings:
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: ~
access_denied_handler: App\Security\AccessDeniedHandler
guard:
authenticators:
- App\Security\UserAuthenticator
logout:
path: app_logout # logout-route
target: app_loggedout # where to go after successful logout
And this is the access_control (also in security.yaml):
access_control:
- { path: ^/login$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/loggedout, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin, roles: ROLE_ADMIN }
- { path: ^/, roles: ROLE_USER }
The class UserAuthenticator is called, users are authenticated automatically (because of the username that is provided in the $_SERVER-variable).
But now: I want the user to be redirected to the original URL after the authentication. E.g. if the user wants to go to SITE/test, this should happen automatically after they pass through the UserAuthenticator.
I have managed to achieve this by using the sf_redirect-cookie which Symfony seems to set automatically, it contains something like this:
{"token":"b2282c","route":"app_some_url","method":"GET","controller":{"class":"App\\Controller\\SecurityController","method":"some_method","file":"<PATH>\\src\\Controller\\SecurityController.php","line":23},"status_code":302,"status_text":"Found"}
In my UserAuthenticator I check if the cookie is there, is filled and has a route set and then return a RedirectRespone leading to the route in onAuthenticationSuccess().
The problem is: While this works fine on Apache (dev-system), the sf_redirect-cookie is missing completely on IIS (prod-system). It's not that IIS would not set cookies at all ($_COOKIE['PHPSESSID'] is there), it's just that sf_redirect is missing.
I've been experimenting with a custom subscriber to the redirect-to-login-event, but I'd rather not use a workaround, so the question is: How can I tell Symfony to set the sf_redirect-cookie on IIS, or how do I need to configure IIS to set it?
You can add TargetPathTrait to your authenticator to redirect the user after successful login.
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
....
return new RedirectResponse($this->getTargetPath($request->getSession(), $providerKey));
....
}
If I have a secured route, let's say like panel from below, Symfony will allow access only to logged in users.
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/panel, role: ROLE_USER }
For users that are not logged in it will always redirect them to the login_path (I'm using FOSUserBundle):
security:
firewalls:
main:
pattern: ^/
form_login:
provider: fos_userbundle
login_path: fos_user_security_login
Where can I disable or override this redirect? I want to show a login form directly, without redirecting the user.
I believe it has to do with AccessDeniedHandlerInterface, but what key needs to be overwritten in security.yml? And where is the default implementation?
For other situations we have DefaultLogoutSuccessHandler, DefaultAuthenticationFailureHandler, DefaultAuthenticationSuccessHandler and we can implement a service for each of these situations, that extends their respective interfaces and can handle the situation in a custom manner. Can't find anything for AccessDenied, though. Its directory contains only the interface.
I would do this manually.
Make your route accessible by anonymous:
- { path: ^/panel, role: [IS_AUTHENTICATED_ANONYMOUSLY, ROLE_USER] }
In your template, check if there is a logged in user:
{% if app.user is null %}
<!-- Then display your login form -->
{% else %}
<!-- Display the normal view -->
{% endif %}
Or do it from the controller:
if (!is_object($this->get('security.token_storage')->getToken()->getUser())) {
// Render the login form
}
Like this, you can make your logic depending on that the user is authenticated or not.
I'm looking for a working solution, to hide pages from authenticated users in symfony. Unfortunately, the default user roles are staggered. The following configuration does not work:
# app/config/security.yml
access_control:
# This rules works not:
- { path: ^/login, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
# This rule works:
- { path: ^/logout$, role: roles: [ROLE_USER] }
For my opinion, this ruleset should end up in a HTTP 404 Unauthorized after visiting /login or /register as a authenticated user (UsernamePasswordToken) - but it does not!
After some reasearch, I found more information. According to Symfony 2 documentation, users are automatically given one of the following roles depending on how they are authenticated:
IS_AUTHENTICATED_REMEMBERED
IS_AUTHENTICATED_ANONYMOUSLY
IS_AUTHENTICATED_FULLY
If you have the IS_AUTHENTICATED_REMEMBERED role, then you also have
the IS_AUTHENTICATED_ANONYMOUSLY role. If you have the
IS_AUTHENTICATED_FULLY role, then you also have the other two roles.
In other words, these roles represent three levels of increasing
"strength" of authentication.
In other words: There seems to be no possible way, to hide pages from a authenticated user...
1. Possible solution - Use a static role (does not work...)
Using the access control role IS_ANONYMOUS could be great option, but it does not work for paths behind a Firewall: Symfony will append a AnonymousToken to your session each time you visit any page behind ^/:
# app/config/security.yml
security:
firewalls:
main:
pattern: ^/
...
2. Possible solution - Edit all controllers (takes way too long...)
I ended up rewriting all controllers (.....) and implemented custom, hard-coded access rules into the controllers.
I hope, somebody has a smiliar problem and a simple stupid solution.
You can easily solve this with the use of the expression-language component ( symfony ~2.4):
access_control:
- { path: ^/whatever, allow_if: "!is_fully_authenticated()" }
For symfony <2.4 you can use JMSSecurityExtraBundle which provides expression-based security rules aswell.
request, token and user are the variables you have access to and
is_anonymous(), is_authenticated(), is_fully_authenticated(),
is_rememberme(), and has_role() are the functions defined in this
context.
Read more about the expression-language:
introduction
documentation
syntax
I have seen some posts in this regard, specifically Auto-Login via URL with symfony2 (which I can't use because I do not know what needs to go into $request) and Automatic post-registration user authentication. I tried the latter, but it is not logging in.
Code from security.yml
firewalls:
admin_login_firewall:
pattern: ^/admin/login$
anonymous: ~
admin:
pattern: ^/admin
form_login:
login_path: admin_login
check_path: admin_login_check
default_target_path: admin_dashboard
logout:
path: admin_logout
target: admin_login
http_basic:
realm: "Licensing Admin Portal"
member_login_firewall:
pattern: ^/members/login$
anonymous: ~
members:
pattern: ^/members
form_login:
login_path: member_login
check_path: member_login_check
default_target_path: member_dashboard
logout:
path: member_logout
target: home
http_basic:
realm: "Licensing Member Portal"
encoders:
Pmb\LicensingBundle\Entity\User: plaintext
access_control:
- { path: ^/admin/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/members/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin, roles: ROLE_ADMIN }
- { path: ^/members/, roles: ROLE_USER }
Code snippet from Controller function saveUserAction():
... // Code preceding this point creates user entity and sets all fields
$em = $this->getDoctrine()->getManager();
if (empty($data['user_id'])) $em->persist($user);
$em->flush();
if (!empty($organization)) $this->linkOrganizationUserAction($organization,$user, true);
if (isset($data['registering']))
{
$token = new UsernamePasswordToken($user, null, 'members', $user->getRoles());
$this->get('security.context')->setToken($token);
$this->get('session')->set('_security_main',serialize($token));
}
return $this->createJsonResponse($user);
I am trying to log in to the members firewall. I do not know enough about this to troubleshoot. Most of this is just copy/paste/edit. Any help / explanation would be greatly appreciated. I also read the article under Symfony2 auto-login after registration, but I do not see the significance of this, as I do not need have users logged in accross different firewalls, and just need the user logged in under the members firewall.
One thing that I DID notice, is that the user entity is having its salt field populated when persiting to the database, even though I did not set a salt and I cannot see anything auto-setting the salt. I am not yet using the salt as I am not yet encrypting my passwords (just trying to get it working with plain text passwords first), and when trying to log in with a created user (which does get created, just not getting logged in) I cannot log in unless I clear the salt on the user. I don't know if this has anything to do with the fact that the auto-login is not working.
The issue here was with the line $this->get('session')->set('_security_main',serialize($token));. The "_main" of "security_main" is also the firewall that you are authenticating against. So it should have been "_security_members". After changing it the code worked as is.
Hi stackoverflow friends,
I have an instance that ,In symfony2 I created a security bundle (not used FOS USER BUNDLE) in which when I logged in, I try to access the login page again the login form is shown.Is there's no redirection to the default page, even if I'm actually logged in. How to prevent this login form ,after logged in.
Below is my security.yml
UPDATED
firewalls:
main:
pattern: ^/
anonymous: ~
form_login:
login_path: /login
check_path: /login_check
logout:
path: /logout
target: /login
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/centerreg, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/customredirect, roles: ROLE_USER }
- { path: ^/admin/, roles: ROLE_ADMIN }
- { path: ^/center/, roles: ROLE_CENTER }
- { path: ^/client/, roles: ROLE_CLIENTADMIN }
- { path: ^/examcenter/, roles: ROLE_EXAMCENTER }
- { path: ^/tutor/, roles: ROLE_TUTOR }
- { path: ^/evaluator/, roles: ROLE_EVALUATOR }
- { path: ^/student/, roles: ROLE_STUDENT }
- { path: ^/user/, roles: ROLE_USER }
Any help would be appreciable.
Symfony won't automatically do this because login page is always accessible as indicated in security.yml:
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
If you don't want authenticated users to get to the login page, you need to manually redirect them away from login page. To do that, go to your Controller for login action and at the beginning of loginAction() function add this:
public function loginAction()
{
if ($this->get('security.context')->isGranted('IS_AUTHENTICATED_FULLY'))
{
// redirect authenticated users to homepage
return $this->redirect($this->generateUrl('_homepage'));
}
//other code goes here...
}
This will redirect authenticated users to your homepage. Of course, replace '_homepage' to route name of a page you wish to redirect users to.
can you update question with your routes?
I think you should have default path (for example, /secure-area) that requires authentication and some other (for example, /secure-area/login) that represents your login form. So, basically, returning visitor would not visit /secure-area/login but /secure-area instead. This way it would not show login for but reload user from session...