0

I am attempting to implement security to restrict access to specific blogs by using USER_ROLE for each user. Each blog page has 1 owner that can post to it.

This is built on what I've learned from the fantastic tutorials from KNP University.

http://knpuniversity.com/screencast/symfony2-ep2

I've set this up using access_control in security.yml to limit access to each user based on their USER_ROLE. (user1 has access to /job1/new and /job1/create in order to create/edit/delete posts on the blog page---only 1 user has access to each blog page)

access_control:
    - { path: ^/job1/new, roles: [ROLE_USER1, ROLE_ADMIN] }
    - { path: ^/job2/new, roles: [ROLE_USER2, ROLE_ADMIN] }
    - { path: ^/job3/new, roles: [ROLE_USER3, ROLE_ADMIN] }
    - { path: ^/job1/create, roles: [ROLE_USER1, ROLE_ADMIN] }
    - { path: ^/job2/create, roles: [ROLE_USER2, ROLE_ADMIN] }
    - { path: ^/job3/create, roles: [ROLE_USER3, ROLE_ADMIN] }

Each /job1, /job2 etc. are separate blog pages. And I am using an if statement in Twig to determine which user has access to create/edit/delete posts.

{% if is_granted('ROLE_USER1') %}
    <li><a href="{{ path('job1_new') }}">Add New Post</a></li>
{% endif %}

The problem is, as I add in more blog pages I will need to create more paths in the access control (e.g., /job4, /job5 etc.) which isn't an ideal solution although it does work.

I have detailed the code out here in the link below, as it was recommended to use security in the controller based on a Disqus conversation 'joe joe' with Ryan Weaver here --- http://knpuniversity.com/screencast/symfony2-ep2

My questions are:

1) Now that I have created a ManyToMany relationship with User and Category how do I setup security in the controller to prevent other users from accessing the create/edit/delete actions that they don't have the roles for?

2) How do I hide the option in Twig for create/edit/delete using this method / also what do I add in the access_control using this approach?

joe joe
  • 13
  • 4

2 Answers2

1

It is unrealistic to grow access control such that it needs to explicitly include each new user. Rather, one can use ROLE_USER to only allow access to editing/creating any entity (e.g., a blog) to an authenticated user. Once the user has authenticated, a controller can provide access to that user's blog entities.

This requires a one-to-many relationship between user and blogs. In the controller, it then becomes a simple matter of something like this:

...
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;

/**
 * ...
 * @Security("has_role('ROLE_USER')")
 */

class BlogifyController extends Controller
{

   public function blogAction
    {
        $user = $this->getUser();
        $blogs = $user->getBlogs();
    // do your form thing, etc.
    ...
    }
}
geoB
  • 4,578
  • 5
  • 37
  • 70
0

I think you should use builtin Voter from Security Bundle. So, you create a Blog entity with 1:1 relationship to User Entity, then create a Voter service, build you logic in vote method, use that voter in controller, that's it. Here is sample example:

class SomeVoter implements VoterInterface
{
    const CREATE = 'create';
    const EDIT = 'edit';
    const DELETE = 'delete';

    /**
     * @param string $attribute
     * @return bool
     */
    public function supportsAttribute($attribute)
    {
        return in_array($attribute, array(
            self::CREATE,
            self::EDIT,
            self::DELETE
        ));
    }

    /**
     * @param string $class
     * @return bool
     */
    public function supportsClass($class)
    {
        $supportedClass = 'Acme\DemoBundle\Entity\Blog';

        return $supportedClass === $class || is_subclass_of($class, $supportedClass);
    }

    /**
     * @param TokenInterface $token
     * @param object $blog
     * @param array $attributes
     * @return int
     */
    public function vote(TokenInterface $token, $blog, array $attributes)
    {
        ....

        $attribute = $attributes[0];
        $user = $token->getUser();

        switch($attribute) {
            case 'edit':
                if ($user->getId() === $blog->getUser()->getId()) {
                    return VoterInterface::ACCESS_GRANTED;
                }
                break;

            ....
        }

        ...
    }
}

controller action:

public function editAction($id)
{
    $blog = ...;

    if (false === $this->get('security.context')->isGranted('edit', $blog)) {
        throw new AccessDeniedException('Unauthorised access!');
    }

    ...
}
xurshid29
  • 4,172
  • 1
  • 20
  • 25