Reputation: 1382
On my site, except some spesific pages (login, register, pwd reset) users are required to login. I have implemented remember me
feature and it works well.
What I would like to achieve is, for administration pages, users should have admin role and not remembered
. To check this requirement I used allow_if
in the relevant access_control rule, however it denies my admin user's access, although session is not remembered and I can confirm that session has UsernamePasswordToken
on debug toolbar.
My access_control rules are as follows: (4th one doesn't work)
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/user/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/user/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin, allow_if: "has_role('ROLE_ADMIN') and has_role('IS_AUTHENTICATED_FULLY')" }
- { path: ^/, role: IS_AUTHENTICATED_REMEMBERED }
If I remove and has_role('IS_AUTHENTICATED_FULLY')
part from the relevant access control rule, user can pass authorization so the problem seems to be this part.
What is the problem with has_role('IS_AUTHENTICATED_FULLY')
?
Symfony Version: 2.7.5
Upvotes: 1
Views: 3154
Reputation: 1382
Well, I found a workaround to fix the issue.
How to use Expressions in Security, Routing, Services, and Validation cookbook article on official website has a relevant section and states the possible use of is_remember_me()
and is_fully_authenticated()
methods for checking the existence IS_AUTHENTICATED_REMEMBERED
and IS_AUTHENTICATED_FULLY
roles respective.
is_remember_me is different than checking IS_AUTHENTICATED_REMEMBERED
The is_remember_me and is_authenticated_fully functions are similar to using IS_AUTHENTICATED_REMEMBERED and IS_AUTHENTICATED_FULLY with the isGranted function - but they are not the same. The following shows the difference:
use Symfony\Component\ExpressionLanguage\Expression;
// ...
$ac = $this->get('security.authorization_checker');
$access1 = $ac->isGranted('IS_AUTHENTICATED_REMEMBERED');
$access2 = $ac->isGranted(new Expression(
'is_remember_me() or is_fully_authenticated()'
));
Here, $access1 and $access2 will be the same value. Unlike the behavior of IS_AUTHENTICATED_REMEMBERED and IS_AUTHENTICATED_FULLY, the is_remember_me function only returns true if the user is authenticated via a remember-me cookie and is_fully_authenticated only returns true if the user has actually logged in during this session (i.e. is full-fledged).
Using that documentation section, I revised my access control rules as follows and it works now:
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/user/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/user/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin, allow_if: "has_role('ROLE_ADMIN') and is_fully_authenticated()" }
- { path: ^/, role: IS_AUTHENTICATED_REMEMBERED }
However, I still think that this is an issue and is not the expected behaviour. So, I opened an issue in the official issue tracker:
Github Issue: #16096 - Expression engine has_role() function can't process implicit roles
Upvotes: 1
Reputation: 3051
Add Code to Deny Access There are two ways to deny access to something:
- access_control in security.yml allows you to protect URL patterns (e.g. /admin/*). This is easy, but less flexible;
- in your code via the security.authorization_checker service.
You're trying to use the first way, but it's possible to make only by second.
You need to perform an authorization checking in your controller by putting inside it a code
if (!$this->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_FULLY')) {
throw $this->createAccessDeniedException();
}
Also you could use SensioFrameworkExtraBundle and just add an annotation to your controller
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
...
/**
* @Security("is_granted('IS_AUTHENTICATED_FULLY')")
*/
public function showAction()
{
}
Upvotes: 0