Authentication index

Hi,

I am using cakephp4.x

How do I apply authentication for index? I have read the CakePHP Authorization 2.x Cookbook and found out that I should use Scope Conditions. But then I am lost. Is there somewhere a minimal example of how to do that or can you tell me? How does the controller function index look like and how the policy (or is it put somewhere else than in policies?).

@Roridula Thanks for bringing this up. I would appreciate some guidance as well.

I want to simply deny access to the user index to everyone but admins.

I’ve create a policy for the index method:

public function canIndex(IdentityInterface $user, User $resource)
{
    return $this->isAdmin($user, $resource);
}

My users controller:

public function index()
{
    $users = $this->Users->find();
    $this->Authorization->applyScope($users);
    $this->set(compact('users'));
}

But I still get:

Policy for App\Model\Table\UsersTable has not been defined.

If, instead of applyScope, I try:

$this->Authorization->authorize($users);

I see:

Policy forCake\ORM\ResultSethas not been defined.

The other policies in the UserPolicy.php are working for the other methods (edit,delete,view,and a custom method), just not for the index.

If anyone could provide some insight into why this happening, I’d very much appreciate it.

Thank you!

Hi,

hope you guys managed to figure this one out, if not, here’s my solution. I’m a beginner in cakePHP, so it might be a bit hacky, but it works for me so far. Anyone with more experience is welcome to correct my mistakes. :slight_smile:
This is my users controller:

public function index()
    {
        $this->paginate = [
            'contain' => ['Movies'],
        ];
        $users = $this->paginate($this->Users);
        $loggedInUserId = $this->request->getAttribute('identity')->id;
        $user = $this->Users->get($loggedInUserId);
        $this->Authorization->authorize($user, 'index');
        $this->set(compact('users', 'user'));
    }

And this is my Policy for the index:

public function canIndex(IdentityInterface $user, User $resource) {
        return $user->admin;
    }

I know it’s not really the solution you were looking for, but I hope it still helps.

How does this code even execute? You haven’t passed anything that the canIndex function can accept in its required $resource parameter. Is there something else happening somewhere that you’re not showing?

It’s important to distinguish between Authentication and Authorization, which I think of as AuthN and AuthZ because… well… syllables.

AuthN identifies a user and decides if they are allowed to visit your site. It is very broad-brush can-you-go-here.

Importantly, it makes an Identity object available for your use in code.

AuthZ is a fine-grain system to decide which resources an authenticated user can gain access to and what they can do with that resource.

@Roridula originally asked about AuthN but needed to be asking about AuthZ.

@allankh and @azothep made the leap to AuthZ but didn’t mention the shift of focus.

If your system’s AuthZ needs were very simple you could satisfy them without installing the AuthZ tools because as @azothep shows, the Identity is available for on-the-spot examination.

But adding AuthZ also adds the can, canResult, and scope methods to the Identity objects and that is the gateway to all the policies.

The questions here have focused on a controller’s index page. In resource terms I think of this as ‘can this actor see an arbitrary list of this record type’.

There’s plenty of named-by-algorithm logic that makes this system work and I think that tripped you up @allankh. You have a canIndex policy but invoke applyScope. Your controller should be:

public function index()
{
    $users = $this->Users->find();

    if (!$this->Authorization->can($users)) {
        //redirect unauthorized visitor
    }

    $this->set(compact('users'));
}

I don’t use the AuthZ component myself so I’m trying to interpret the docs with no use-experience but:

The can() call’s first argument is the resource you are considering, the second arg is assumed to be the current action. So the call becomes $this->Authorization->can($users, 'index') (@azothep’s code makes this explicit). And, internally, the current Identity will be used; that’s the current actor/visitor.

I like to make the policy calls using the Identity object because it is clearer to me:

public function index()
{
    $users = $this->Users->find();

    if (!$this->identity->can('index', $users)) {
        //redirect unauthorized visitor
    }

    $this->set(compact('users'));
}

//in AppController I have
public function identity() {
   return $this->getRequest()->getAttribute('identity');
}

One important point regarding the code @azothep and @allankh posted, the can() policies will return True/False so you need to add something to handle the disallowed cases. I suggested a redirect.

There is a ton more that could be said. But that roughly covers most of the points raised here. But I’ll leave you with this link to the Middleware specifically designed to implement Controller/Action authorization.