I have successfully install Yii-Rights modules with Yii-Users.
I have:-
Create a Roles (Authenticated)
Give permission to certain controller.action (Campaign.index)
However, when i login to the system as "Authenticated" roles, (I'm sure rights is working fine in the login, since i redirect the user by the roles), the Campaign.index return Error 403 -> You are not authorized to perform this action.
However when "Admin" roles go into the controller it working just fine. I noticed there is a way to allow the user to enter the controller, with allowedaction(), but when i logout and enter the function, it displays. So, It is not a solution.
In my Controller, i have
class CampaignController extends RController {
/**
* #var string the default layout for the views. Defaults to '//layouts/column2', meaning
* using two-column layout. See 'protected/views/layouts/column2.php'.
*/
public $layout = '//client/dashboard';
/**
* #return array action filters
*/
public function filters() {
return array(
'rights', // perform access control for CRUD operations
//'postOnly + delete', // we only allow deletion via POST request
);
}
/**
* Specifies the access control rules.
* This method is used by the 'accessControl' filter.
* #return array access control rules
*/
public function accessRules() {
return array(
array('allow', // allow all users to perform 'index' and 'view' actions
'actions' => array('index', 'view', 'create', 'update'),
'users' => array('#'),
),
array('allow', // allow admin user to perform 'admin' and 'delete' actions
'actions' => array('admin', 'delete'),
'users' => array('admin'),
),
array('deny', // deny all users
'users' => array('*'),
),
);
}
I have read most of the web regarding to this topic, but i found none that have the same problem like i do. I have tried uninstall the module, and install back but no luck.
Im using Yii 1.1.14 and the latest Yii-rights downloaded from https://bitbucket.org/Crisu83/yii-rights/ (Last updated 2014-02-20)
Please help me define my problems.
Thank you. :)
Related
I am working on a Laravel 8 project. I have noticed that a couple of things have changed including authentication. I am using Jetstream for authentication.
I have installed the Jetstream and I can register and login going to the route /register and /login on the browser. What I am doing now is that for local development, I am creating seeder class so that I can seed the users and log in using those seeded users for local development. But when I log in using those account, it is always complaining that "These credentials do not match our records.".
This is what I have done. I have registered an account on browser using password, "Testing1234". The password hash is saved in the users table. I copied the password and use it in the UserFactory class as follow.
<?php
namespace Database\Factories;
use App\Models\Role;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
class UserFactory extends Factory
{
use WithFaker;
/**
* The name of the factory's corresponding model.
*
* #var string
*/
protected $model = User::class;
/**
* Define the model's default state.
*
* #return array
*/
public function definition()
{
return [
'name' => $this->faker->name,
'email' => $this->faker->unique()->safeEmail,
'email_verified_at' => now(),
'password' => '$2y$10$tive4vPDzIq02SVERWxkYOAeXeaToAv57KQeF1kXXU7nogh60fYO2', //Testing.1234
'remember_token' => Str::random(10),
];
}
}
Then I created a user using factory as follow.
User::factory()->create(['email' => 'testing#gmail.com']);
Then I tried to log in using the user I just created. But it is always complaining, "These credentials do not match our records.". I cannot use the other passwords too. Even the default password that comes with the default user factory class. What is wrong with my code and how can I fix it?
Try using
User::factory()->make([
'email' => 'testing#gmail.com',
]);
I have finally found the issue.
In the JetstreamServiceProvider class, I have added the following code to customise the login flow.
Fortify::authenticateUsing(function (Request $request) {
});
My bad. That is what makes it failing.
I've created a simple test site using CakePHP 3.8 and Authentication 1.0 to try it out. I'd like to use both Form and Basic authentication since the intended app will offer REST calls.
The site works properly if the HttpBasic is not included, that is the Login window is displayed. However, with HttpBasic, the site goes directly to basic authentication.
The code is directly from the cookbook.
What am I missing?
public function getAuthenticationService(ServerRequestInterface $request, ResponseInterface $response)
{
$service = new AuthenticationService();
$service->setConfig([
'unauthenticatedRedirect' => '/users/login',
'queryParam' => 'redirect'
]);
$fields = [
'username' => 'user',
'password' => 'password',
];
// Load Identifiers
$service->loadIdentifier('Authentication.Password', compact('fields'));
// Load the authenticators
$service->loadAuthenticator('Authentication.Session');
$service->loadAuthenticator('Authentication.Form', [
'fields' => $fields,
'loginUrl' => '/users/login',
]);
$service->loadAuthenticator('Authentication.HttpBasic');
return $service;
}
As mentioned in the comments, using the form authenticator and the HTTP basic authenticator together won't work overly well, this is due to the fact that the authentication service won't stop executing all loaded authenticators, unless one of them returns a response that indicates successful authentication.
This means that you'd always be presented with the authentication challenge response, and never see your login form. Only the actual authentication part would work in that constellation, ie directly sending your login credentials as form data to the login endpoint.
If you don't actually need the basic auth challenge response that is preventing you from accessing the login form, then you could use a custom/extended authenticator that doesn't cause a challenge response to be returned, which should be as simple as overriding \Authentication\Authenticator\HttpBasicAuthenticator::unauthorizedChallenge():
src/Authenticator/ChallengelessHttpBasicAuthenticator.php
namespace App\Authenticator;
use Authentication\Authenticator\HttpBasicAuthenticator;
use Psr\Http\Message\ServerRequestInterface;
class ChallengelessHttpBasicAuthenticator extends HttpBasicAuthenticator
{
public function unauthorizedChallenge(ServerRequestInterface $request)
{
// noop
}
}
$service->loadAuthenticator(\App\Authenticator\ChallengelessHttpBasicAuthenticator::class);
Also not that you might need to add additional checks in case your application uses the authentication component's setIdentity() method, which would cause the identity to be persisted in the session, even when using stateless authenticators. If you don't want that, then you'd need to test whether the successful authenticator is stateless before setting the identity:
$provider = $this->Authentication->getAuthenticationService()->getAuthenticationProvider();
if (!($provider instanceof \Authentication\Authenticator\StatelessInterface))
{
$this->Authentication->setIdentity(/* ... */);
}
With CakePHP 3 we used Auth component and this worked like this CakePHP - How to allow unauthenticated access to specific pages
Now I'm trying to use the new Authentication and Authorization plugins instead (I don't know if it is the best solution).
I have this case:
I have some tables in the database for entities (cars, brands, and users). I have users and 4 level user roles (pyramid).
- Admins can change everything
- Editors can see and add brands and cars, but only can edit or update cars and brands created by themselves.
- Registered users can add only cars and edit their cars (and see all cars and brands).
- Anonymous users can see all but only can create a user account.
Authentication works well alone. To allow anonymous user access to content I use $this->Authentication->allowUnauthenticated(['login', 'add']); but when I load Authorization plugin, everything give error.
Do I need to specify all Authorization access with authorizeModel and other functions? There is a way to authorize at the same time with both plugins? Do I really need Authorization plugin for this and is recommended or Authentication plugin can handle this?
With previous Auth component I worked with something like this piece of code:
In AppController.php
public function beforeFilter(Event $event)
{
$this->Auth->allow(['view', 'display']);
}
public function isAuthorized($user)
{
return true;
}
In UsersController.php
public function beforeFilter(Event $event)
{
parent::beforeFilter($event);
$this->Auth->allow('add', 'logout');
}
In Cars and Brands controllers
public function isAuthorized($user)
{
if (isset($authUser['role']) && $authUser['role'] === 'admin') {
return true;
}
if ($this->request->action === 'add') {
return true;
}
if ($this->request->action === 'index') {
return true;
}
if (in_array($this->request->action, ['edit'])) {
$carId = (int)$this->request->params['pass'][0];
if ($this->Cars->exists(['id' => $carId, 'user_id' => $authUser['id']])) {
return true;
}
}
return false;
}
Followed from https://book.cakephp.org/3/es/tutorials-and-examples/blog-auth-example/auth.html
My versions are:
- CakePHP 3.8
- Authentication plugin 1.4
- Authorization plugin 1.3
Sorry if my question is a bit basic but documentation is not very clear with this. I can add more details if needed.
Edit: If I quit unauthenticatedRedirect I get:
No identity found. You can skip this check by configuring `requireIdentity` to be `false`.
Authentication\Authenticator\UnauthenticatedException
If I add requireItentity as false, in AppController
$this->loadComponent('Authentication.Authentication', [
'requireIdentity' => false
]);
I get (where / is the path, can be /cars /brands)
The request to `/` did not apply any authorization checks.
Authorization\Exception\AuthorizationRequiredException
If I use this in AppController (always Authentication before Authorization)
$this->loadComponent('Authentication.Authentication', [
'requireIdentity' => false
]);
$this->loadComponent('Authorization.Authorization', [
'skipAuthorization' => [
'login',
]
]);
and this in Application
$service->setConfig([
'unauthenticatedRedirect' => \Cake\Routing\Router::url('/users/login'),
'queryParam' => 'redirect',
]);
I send all users to login page but authorization checks error appears.
With $this->Authorization->skipAuthorization(); in beforeFilter() user can see the pages and works but I don't know if it is appropriated.
If I use this in any controller beforeFilter $this->Authorization->authorizeModel('index', 'add', 'display' ...);
I get
Policy for `App\Model\Table\CarsTable` has not been defined.
Authorization\Policy\Exception\MissingPolicyException
In home (or pages controller) I get
Policy for `Cake\ORM\Table` has not been defined.
Authorization\Policy\Exception\MissingPolicyException
Do I really need to create policies for each table? I think is more complex than previous Auth component or maybe I'm doing something wrong.
I need a solution where I can restrict the user to save any data when he is been deactivated by the admin. Suppose the user is active on a page where he is going to save a form but at the same instance admin has deactivated him. so , now when he try to save the form , he should be redirected to the login page saying "Your account is been deactivated, contact the support", without saving the data. I am working in cakephp 3.x . I tried to use beforeFilter for it. But it is deactivating the user but also the user is able to save the data.
I had a similar situation. I added a custom finder to the auth component to restrict deactivated users from making requests when they were deactivated but it only stopped deactivated users from logging in and NOT immediately restricting them from making any request. This meant a deactivated user could still access the application for the remainder of their session. (A lot of havoc can be caused by a disgruntled deactivated employee in say 10 hours.)
My solution was to tell the auth component to use controller hook methods for authorization. Cookbook info here
App Controller - Initialize action - Auth Component
$this->loadComponent('Auth', [
'authorize' => 'Controller', // ADDED THIS LINE
'authenticate' => [
'Form' => [
'finder' => 'active' // Custom finder to retrieve details for login of active users - for login only.
]
],
// Other auth component actions here
]);
And this is what logs the user out immediately
App Controller - isAuthorized
public function isAuthorized()
{
if ($this->checkActiveAndRole() === true) {
return true;
}
return false;
}
App Controller - checkActiveAndRole - (Streamlined for this post)
private function checkActiveAndRole()
{
// Initialise and validate the id from auth component.
$id = $this->Auth->user('id');
// Select the users status and role.
$Users = TableRegistry::getTableLocator()->get('Users');
$query = $Users->find('statusRole', [
'id' => $id
]);
if ($query->isEmpty()) {
return false;
}
$status = 0;
foreach ($query as $row):
$status = $row->status;
endforeach;
// Check if the user is active.
if ($status === 0) {
return false;
}
return true;
}
And this worked for me. Ie: Checking if the user is active on every request with the isAuthorized() function in the app controller
I have a requirement that checks if the current loged in user is a payed member or not for a set of action. if the user in not a payed member then he has to be sent to the take membership page. following is the code. In the controller (Yii framework )
public function accessRules()
{ return array(
array('allow',
'actions'=>array('enroll','index','admin','suggesttags'),
'users'=>array('#'),
),
array('allow',
'actions'=>array('view', 'read'),
'users'=>array(Yii::app()->user->name),
'expression' => 'Yii::app()->controller->hasPaied()'
),
now the hasPayed() functions returns false for unpaid member and at present user is redirected to 403 exception.
I want to customize the 403 exception page to 'take membership' page. Is there a way to do it? so that all the exception raised from this specific controller\action are send to the take membership page and rest 403 exception remain unchanged ?
Try using deniedCallback from CAccessControlerFilter.
// optional, the denied method callback name, that will be called once the
// access is denied, instead of showing the customized error message. It can also be
// a valid PHP callback, including class method name (array(ClassName/Object, MethodName)),
// or anonymous function (PHP 5.3.0+). The function/method signature should be as follows:
// function foo($user, $rule) { ... }
// where $user is the current application user object and $rule is this access rule.
// This option is available since version 1.1.11.
'deniedCallback'=>'redirectToDeniedMethod',