Closed mike240se closed 4 years ago
Here in the troubleshooting guide https://github.com/scheb/two-factor-bundle/blob/master/Resources/doc/troubleshooting.md it says:
The page you've seen after login doesn't require a fully authenticated user. Most likely that path is accessible to IS_AUTHENTICATED_ANONYMOUSLY via your security access_control configuration. Either change your access_control configuration or after login force-redirect to user to a page that requires full authentication.
I believe that's the problem.
Here in the troubleshooting guide https://github.com/scheb/two-factor-bundle/blob/master/Resources/doc/troubleshooting.md it says:
The page you've seen after login doesn't require a fully authenticated user. Most likely that path is accessible to IS_AUTHENTICATED_ANONYMOUSLY via your security access_control configuration. Either change your access_control configuration or after login force-redirect to user to a page that requires full authentication.
I believe that's the problem.
i'm so sorry i forgot to include i already went through the trouble shooting guide (and read every relevant closed issue) and didnt find a fix.
its not that, if i try to access authenticated part of the site after logging in, i get the login prompt again. if i login again, again i am redirected to the start page of the app.
I think I found the issue. the install docs for e-mail say to use:
security:
firewalls:
main:
two_factor:
auth_form_path: 2fa_login # The route name you have used in the routes.yaml
check_path: 2fa_login_check # The route name you have used in the routes.yaml
but when i check the config reference it shows as:
auth_form_path: /2fa # Path or route name of the two-factor form
check_path: /2fa_check # Path or route name of the two-factor code check
When i changed from 2fa_login (route name) to /2fa (path) it started working as expected....
I pasted this in my app/config/routing.yml:
2fa_login:
path: /2fa
defaults:
_controller: "scheb_two_factor.form_controller:form"
2fa_login_check:
path: /2fa_check
EDIT: I am not sure why but it worked once after i made this changed and now does the same as before. back to square one.
If you're using a path or the route name in the configuration shouldn't make a difference. The route name is definitely the cleaner solution.
Would you please show me your security.yaml configuration, all of it.
Here it is:
security:
encoders:
# Symfony\Component\Security\Core\User\User: plaintext
AdminBundle\Entity\User:
algorithm: bcrypt
role_hierarchy:
ROLE_SUPPORT: [ROLE_USER]
ROLE_ADMIN: [ROLE_USER, ROLE_SUPPORT]
ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
# http://symfony.com/doc/current/security.html#b-configuring-how-users-are-loaded
providers:
administrators:
entity: { class: AdminBundle:User, property: username }
# users:
# entity: { class: PrivateBundle:User, property: username }
firewalls:
# disables authentication for assets and the profiler, adapt it according to your needs
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
#main:
# anonymous: ~
# login:
# two_factor:
# auth_form_path: 2fa_login # The route name you have used in the routes.yaml
# check_path: 2fa_login_check # The route name you have used in the routes.yaml
#attern: ^/admin/login$
#ecurity: false
#nonymous: ~
secured_area:
two_factor:
auth_form_path: /2fa # The route name you have used in the routes.yaml
check_path: /2fa_check # The route name you have used in the routes.yaml
pattern: ^/
form_login: ~
logout: true
anonymous: ~
logout_on_user_change: true
user_checker: adminbundle.userchecker
access_control:
- { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY , requires_channel: https } #, requires_channel: https, host: example\.org$
- { path: ^/2fa, role: IS_AUTHENTICATED_2FA_IN_PROGRESS }
#- { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: http, host: localhost$ }
- { path: ^/admin/login, roles: IS_AUTHENTICATED_ANONYMOUSLY } #, requires_channel: https
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/logout, role: IS_AUTHENTICATED_ANONYMOUSLY }
#- { path: ^/admin/login, roles: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: http, host: localhost$ }
- { path: ^/admin/, roles: ROLE_ADMIN } # , requires_channel: https
- { path: ^/private/, roles: ROLE_SUPPORT }
- { path: ^/user/, roles: ROLE_USER }
# This makes the logout route available during two-factor authentication, allows the user to cancel
# This ensures that the form can only be accessed when two-factor authentication is in progress
you can see at one point i had 2 firewalls, a seperate for the login, i combined them as your bundle requires yet still it doesnt work.
if i visit any secure part of the site i get redirected back to the login path or the app start path (unsecure area)
This looks odd to me:
access_control:
- { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY , requires_channel: https } #, requires_channel: https, host: example\.org$
Having this as your first rule in the access_contol
list makes this the first rule that is checked (access_contol
is check in order). The pattern path: ^/
matches any path, so this rule always matches and all the following rules are impossible to be reached.
I'd recommend to move this rule to the very bottom of the list, so all the more specific rules are checked first and this is only the last rule to be applied.
Let's see if that changes anything for you.
Note: I replaced your hostname with example.org
, not everyone on Github needs to know the URL to your website ;)
This looks odd to me:
access_control: - { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY , requires_channel: https } #, requires_channel: https, host: example\.org$
Having this as your first rule in the
access_contol
list makes this the first rule that is checked (access_contol
is check in order). The patternpath: ^/
matches any path, so this rule always matches and all the following rules are impossible to be reached.I'd recommend to move this rule to the very bottom of the list, so all the more specific rules are checked first and this is only the last rule to be applied.
Let's see if that changes anything for you.
Note: I replaced your hostname with
example.org
, not everyone on Github needs to know the URL to your website ;)
Thanks you were too quick, i edited it when i noticed but you had already replied! Thanks i appreciate it.
I have that rule so that people can visit the start page of the app without being logged in path / -- this is how i have been doing it for years, is it bad practice the way i am handling it?
I will move the rule to the bottom and try, i did experiment with moving the rules around as i saw in other closed issues a lot of people you helped had issues with the order of the access rules. I am not sure if i tried moving it to the bottom though, trying that now.
I changed it and it still does the same thing. I login, it redirects me to path / but I am partially authenticated and have the 2factortoken, if i go to /2fa i get the e-mail and can then login.
TwoFactorToken {#248 ▼ -authenticatedToken: UsernamePasswordToken {#249 …} -credentials: null -providerKey: "secured_area" -attributes: [] -twoFactorProviders: [▶] }
Roles: None
It looks like the 2fa partially authenticated role is not being assigned?
I have that rule so that people can visit the start page of the app without being logged in path / -- this is how i have been doing it for years, is it bad practice the way i am handling it? Nothing wrong with that approach. It's just that the order of access control rules matters and having this rule first will make all following rules obsolete. So you should change the order.
Side note: I believe, you actually don't need it at all, because every path that doesn't match a access control rule is accessible anyways. My little test app doesn't have such a rule and I can still access any path that isn't explicitly protected => https://github.com/scheb/two-factor-app/blob/master/config/packages/security.yaml
It looks like the 2fa partially authenticated role is not being assigned? It's not a role, it's an attribute (similar to
IS_AUTHENTICATED_ANONYMOUSLY
) that is internally evaluated. It doesn't need to present on the user entity.
So let's proceed:
Now that you moved the rule to the bottom (you did, right?), can you try to access a page that requires you to be logged in, such as /user/
. Does that redirect you to the 2fa form?
I have that rule so that people can visit the start page of the app without being logged in path / -- this is how i have been doing it for years, is it bad practice the way i am handling it? Nothing wrong with that approach. It's just that the order of access control rules matters and having this rule first will make all following rules obsolete. So you should change the order.
Side note: I believe, you actually don't need it at all, because every path that doesn't match a access control rule is accessible anyways. My little test app doesn't have such a rule and I can still access any path that isn't explicitly protected => https://github.com/scheb/two-factor-app/blob/master/config/packages/security.yaml
It looks like the 2fa partially authenticated role is not being assigned? It's not a role, it's an attribute (similar to
IS_AUTHENTICATED_ANONYMOUSLY
) that is internally evaluated. It doesn't need to present on the user entity.So let's proceed:
Now that you moved the rule to the bottom (you did, right?), can you try to access a page that requires you to be logged in, such as
/user/
. Does that redirect you to the 2fa form?
YES, it works! If i try to access /admin after logging in and getting redirecfted to / it sends me to /2fa
Should i remove that rule entirely now? (its at the bottom now)
Also should clarify i am still getting redirected to / after logging in, its just that now if i go to /admin it loads /2fa for me.
Great news, anticipating your next message being to remove that access control rule entirely, i deleted it and now everyhing is working perfect! Thank you!
Instead of opening another question or adding to a closed one, i had a question about resending the e-mail code. SOmeone requested it and you said its easy to just resend it ourselves, which it is but i am wondering what role should the user have at that point and could i use it to secure the controller method?
If the user is in the middle of two-factor authentication, it has the IS_AUTHENTICATED_2FA_IN_PROGRESS
attribute, so I'd use that one.
If the user is in the middle of two-factor authentication, it has the
IS_AUTHENTICATED_2FA_IN_PROGRESS
attribute, so I'd use that one.
Thanks!
If the user is in the middle of two-factor authentication, it has the
IS_AUTHENTICATED_2FA_IN_PROGRESS
attribute, so I'd use that one.
So i added a button to the 2FA form that says "resend e-mail with code" and that fires a simple controller method that just sends an email. But it doesnt work..... /resend2FA/{userid} is the path and its not in a protected area of the site. I originally had it protected with IS_AUTHENTICATED_2FA_IN_PROGRESS but even after removing that completely, when i try to call that method it just redirects to /2FA
so my question is, once in the middle of 2fa verification, does your bundle then redirect any other traffic to /2fa?
It sure seems like this is related to my first issue but i dont see how at this point, i did not change my security and /resend2FA/{userid} should not be protected.
So i had to add to the top of my security.yml access control
I am not sure why. /resend2FA does not fall under any protected routes, i would expect it to work just like the other public parts of my site. not sure what i am missing here.......
Well, I don't know either. Works for me in my little test application.
I am running into a new problem today, getting lots of access denied while testing, would this be related to 2FA you think (or the changes i made to security.yml?) I want to make sure i am not chasing my tail looking for a red herring:
[2020-03-25 15:04:39] security.DEBUG: Read existing security token from the session. {"key":"_security_secured_area","token_class":"Symfony\\Component\\Security\\Core\\Authentication\\Token\\Usern amePasswordToken"} [] [2020-03-25 15:04:39] security.DEBUG: User was reloaded from a user provider. {"provider":"Symfony\\Bridge\\Doctrine\\Security\\User\\EntityUserProvider","username":"testuser"} [] **[2020-03-25 15:04:39] security.DEBUG: Access denied, the user is neither anonymous, nor remember-me. {"exception":"[object] (Symfony\\Component\\Security\\Core\\Exception\\AccessDeniedException(co de: 403): Access Denied. at /var/www/sncirs/vendor/symfony/symfony/src/Symfony/Component/Security/Http/Firewall/AccessListener.php:68)"} []** [2020-03-25 15:04:39] request.ERROR: Uncaught PHP Exception Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException: "Access Denied." at /var/www/sncirs/vendor/symfony/symfony/src/Symfony /Component/Security/Http/Firewall/ExceptionListener.php line 128 {"exception":"[object] (Symfony\\Component\\HttpKernel\\Exception\\AccessDeniedHttpException(code: 0): Access Denied. at /var/www/s ncirs/vendor/symfony/symfony/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php:128, Symfony\\Component\\Security\\Core\\Exception\\AccessDeniedException(code: 403): Access Denied. at /var/www/sncirs/vendor/symfony/symfony/src/Symfony/Component/Security/Http/Firewall/AccessListener.php:68)"} [] [2020-03-25 15:04:39] security.DEBUG: Stored the security token in the session. {"key":"_security_secured_area"} []
Looks like something in your access_control
configuration says you shouldn't have access to this path.
=> Find out which rule matches the path (remember: they're checked in order) and then check if your current user (looks like the username is "testuser") has the required roles.
Thanks Scheb, probably my access control was always a bit off and now that i added 2FA bundle its more obvious :)
Yeah you were right (again). The issue is that in addition to that ^/ access rule we deleted previously, i also had in there these `- { path: ^/admin/, roles: ROLE_ADMIN } # , requires_channel: https
and for routing i had this:
`private: resource: "@PrivateBundle/Controller/" type: annotation prefix: /private
public: resource: "@PublicBundle/Controller/" type: annotation prefix: /
admin: resource: "@AdminBundle/Controller/" type: annotation prefix: /admin`
but then, i had some methods in AdminBundle (under /admin and requring ROLE_ADMIN) that i gave permission to non-admin users. I use frame work extra bundle @Security("has_role('ROLE_ADMIN')")
to protect all my methods. so i had changed from has_role(admin) to has_role(support-lower role).
For whatever reason this worked up until now and either removing that rule i didnt need ^/ OR updating symfony version 3.4.21 to latest cause it to stop allowing that to happen.
unless i am missing something, I am thinking since I already protect every method individually i can just remove these lines
`- { path: ^/admin/, roles: ROLE_ADMIN } ,
Would you mind recommending how you would fix it? do you typically protect areas with access control or use the per method has_role?
I want to try to get back to best practices after so many years of bad habits and carrying over old stuff from early symfony2 days.
thanks again
EDIT: I am thinking the problem with removing those rules is if I accidentally foget to protect a method i now have a security hole..... having those access control rules for areas of the site were kind of like blanket catch alls. I am thinking instead of removing them, I should change them to require the lowest role level that the methods in the area allow. so reduce role_admin to role_user.
EDIT: I am thinking the problem with removing those rules is if I accidentally foget to protect a method i now have a security hole..... having those access control rules for areas of the site were kind of like blanket catch alls. I am thinking instead of removing them, I should change them to require the lowest role level that the methods in the area allow. so reduce role_admin to role_user.
This sounds reasonable. To have access_control
apply the minimum required role for that area, but do the fine-grained control on the per action level. But what do I know, I also haven't built a real Symfony application in the last 5 years :D
got everything working great now, thanks much for your help!
Bundle version: 4.0.14 Symfony version: 3.4.35
I installed everyhing and setup email support and when i login it redirects back to my apps home page. The token is set for your bundle and the user is partially logged in (it shows username in the dev bar). I cant get to any secure part of the site. If I visit mysite.com/2fa it will show me the 2fa and i can use it and it all works.
So the only issue is that while logging in it redirects to the wrong place:
i am using the default routes you provide.