I did a fresh installation. CakePHP 3.6 and CakeDC/Users everything following the docs. I have created custom UsersController.php with the traits for users administration under the admin prefix and after logged in with superuser (created from command line) I managed to create new user with "admin" role. Then logged out and logged in with the new user and browser shows "The page isn’t redirecting properly" error. Social login is disable.
/src/Config/bootstrap.php
...
Configure::write('Users.roles', ['superuser', 'admin', 'user']);
Configure::write('Users.config', ['users']);
Plugin::load('CakeDC/Users', ['routes' => true, 'bootstrap' => true]);
...
/src/Config/users.php
<?php
/**
* Copyright 2010 - 2017, Cake Development Corporation (https://www.cakedc.com)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2010 - 2017, Cake Development Corporation (https://www.cakedc.com)
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
use Cake\Core\Configure;
use Cake\Routing\Router;
$config = [
'Users' => [
// Table used to manage users
'table' => 'CakeDC/Users.Users',
// Controller used to manage users plugin features & actions
'controller' => 'CakeDC/Users.Users',
// configure Auth component
'auth' => true,
// Password Hasher
'passwordHasher' => '\Cake\Auth\DefaultPasswordHasher',
// token expiration, 1 hour
'Token' => ['expiration' => 3600],
'Email' => [
// determines if the user should include email
'required' => true,
// determines if registration workflow includes email validation
'validate' => true,
],
'Registration' => [
// determines if the register is enabled
'active' => false,
// determines if the reCaptcha is enabled for registration
'reCaptcha' => true,
// allow a logged in user to access the registration form
'allowLoggedIn' => false,
//ensure user is active (confirmed email) to reset his password
'ensureActive' => false,
// default role name used in registration
'defaultRole' => 'user',
],
'reCaptcha' => [
// reCaptcha key goes here
'key' => null,
// reCaptcha secret
'secret' => null,
// use reCaptcha in registration
'registration' => false,
// use reCaptcha in login, valid values are false, true
'login' => false,
],
'Tos' => [
// determines if the user should include tos accepted
'required' => true,
],
'Social' => [
// enable social login
'login' => false,
// enable social login
'authenticator' => 'CakeDC/Users.Social',
],
'GoogleAuthenticator' => [
// enable Google Authenticator
'login' => false,
'issuer' => null,
// The number of digits the resulting codes will be
'digits' => 6,
// The number of seconds a code will be valid
'period' => 30,
// The algorithm used
'algorithm' => 'sha1',
// QR-code provider (more on this later)
'qrcodeprovider' => null,
// Random Number Generator provider (more on this later)
'rngprovider' => null
],
'Profile' => [
// Allow view other users profiles
'viewOthers' => false,
'route' => ['plugin' => 'CakeDC/Users', 'controller' => 'Users', 'action' => 'profile'],
],
'Key' => [
'Session' => [
// session key to store the social auth data
'social' => 'Users.social',
// userId key used in reset password workflow
'resetPasswordUserId' => 'Users.resetPasswordUserId',
],
// form key to store the social auth data
'Form' => [
'social' => 'social'
],
'Data' => [
// data key to store the users email
'email' => 'email',
// data key to store email coming from social networks
'socialEmail' => 'info.email',
// data key to check if the remember me option is enabled
'rememberMe' => 'remember_me',
],
],
// Avatar placeholder
'Avatar' => ['placeholder' => 'CakeDC/Users.avatar_placeholder.png'],
'RememberMe' => [
// configure Remember Me component
'active' => false,
'checked' => true,
'Cookie' => [
'name' => 'remember_me',
'Config' => [
'expires' => '1 month',
'httpOnly' => true,
]
]
],
],
'GoogleAuthenticator' => [
'verifyAction' => [
'plugin' => 'CakeDC/Users',
'controller' => 'Users',
'action' => 'verify',
'prefix' => false,
],
],
// default configuration used to auto-load the Auth Component, override to change the way Auth works
'Auth' => [
'loginAction' => [
'plugin' => 'CakeDC/Users',
'controller' => 'Users',
'action' => 'login',
'prefix' => false
],
'loginRedirect' => [
'prefix' => 'admin',
'plugin' => 'Articles',
'controller' => 'Articles',
'action' => 'index'
],
'authenticate' => [
'all' => [
'finder' => 'auth',
],
'CakeDC/Auth.ApiKey',
'CakeDC/Auth.RememberMe',
'Form' => [
'fields' => [
'username' => 'email'
]
],
],
'authorize' => [
'CakeDC/Auth.Superuser',
'CakeDC/Auth.SimpleRbac',
],
],
'OAuth' => [
'path' => ['plugin' => 'CakeDC/Users', 'controller' => 'Users', 'action' => 'socialLogin', 'prefix' => null],
'providers' => [
'facebook' => [
'className' => 'League\OAuth2\Client\Provider\Facebook',
'options' => [
'graphApiVersion' => 'v2.8', //bio field was deprecated on >= v2.8
'redirectUri' => Router::fullBaseUrl() . '/auth/facebook',
'linkSocialUri' => Router::fullBaseUrl() . '/link-social/facebook',
'callbackLinkSocialUri' => Router::fullBaseUrl() . '/callback-link-social/facebook',
]
],
'twitter' => [
'options' => [
'redirectUri' => Router::fullBaseUrl() . '/auth/twitter',
'linkSocialUri' => Router::fullBaseUrl() . '/link-social/twitter',
'callbackLinkSocialUri' => Router::fullBaseUrl() . '/callback-link-social/twitter',
]
],
'linkedIn' => [
'className' => 'League\OAuth2\Client\Provider\LinkedIn',
'options' => [
'redirectUri' => Router::fullBaseUrl() . '/auth/linkedIn',
'linkSocialUri' => Router::fullBaseUrl() . '/link-social/linkedIn',
'callbackLinkSocialUri' => Router::fullBaseUrl() . '/callback-link-social/linkedIn',
]
],
'instagram' => [
'className' => 'League\OAuth2\Client\Provider\Instagram',
'options' => [
'redirectUri' => Router::fullBaseUrl() . '/auth/instagram',
'linkSocialUri' => Router::fullBaseUrl() . '/link-social/instagram',
'callbackLinkSocialUri' => Router::fullBaseUrl() . '/callback-link-social/instagram',
]
],
'google' => [
'className' => 'League\OAuth2\Client\Provider\Google',
'options' => [
'userFields' => ['url', 'aboutMe'],
'redirectUri' => Router::fullBaseUrl() . '/auth/google',
'linkSocialUri' => Router::fullBaseUrl() . '/link-social/google',
'callbackLinkSocialUri' => Router::fullBaseUrl() . '/callback-link-social/google',
]
],
'amazon' => [
'className' => 'Luchianenco\OAuth2\Client\Provider\Amazon',
'options' => [
'redirectUri' => Router::fullBaseUrl() . '/auth/amazon',
'linkSocialUri' => Router::fullBaseUrl() . '/link-social/amazon',
'callbackLinkSocialUri' => Router::fullBaseUrl() . '/callback-link-social/amazon',
]
],
],
]
];
return $config;
/src/Config/permissions.php
<?php
return [
'Users.SimpleRbac.permissions' => [
//admin role allowed to all the things
[
'role' => [GROUP_SUPER_ID, GROUP_ADMIN_ID],
'prefix' => '*',
'extension' => '*',
'plugin' => '*',
'controller' => '*',
'action' => '*'
],
//specific actions allowed for the all roles in Users plugin
[
'role' => '*',
'plugin' => 'CakeDC/Users',
'controller' => 'Users',
'action' => ['profile', 'logout', 'linkSocial', 'callbackLinkSocial'],
],
[
'role' => '*',
'plugin' => 'CakeDC/Users',
'controller' => 'Users',
'action' => 'resetGoogleAuthenticator',
'allowed' => function (array $user, $role, \Cake\Http\ServerRequest $request) {
$userId = \Cake\Utility\Hash::get($request->getAttribute('params'), 'pass.0');
if (!empty($userId) && !empty($user)) {
return $userId === $user['id'];
}
return false;
}
],
//all roles allowed to Pages/display
[
'role' => '*',
//'plugin' => null,
'controller' => 'Pages',
'action' => 'display',
]
]
];
/src/Controllers/Admin/UsersController.php
<?php
namespace App\Controller\Admin;
use App\Controller\Admin\AppController;
use CakeDC\Users\Controller\Traits\ProfileTrait;
use CakeDC\Users\Controller\Traits\SimpleCrudTrait;
use CakeDC\Users\Model\Table\UsersTable;
use Cake\Utility\Inflector;
/**
* Users Controller
*
*
* @method \App\Model\Entity\User[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = [])
*/
class UsersController extends AppController
{
use ProfileTrait;
use SimpleCrudTrait {
index as protected traitIndex;
add as protected traitAdd;
edit as protected traitEdit;
}
public function index()
{
$table = $this->loadModel();
$authUser = $this->Auth->user();
$conditions = [];
if ($authUser['role'] != GROUP_SUPER_ID) {
$conditions['role !='] = GROUP_SUPER_ID;
}
$tableAlias = $table->alias();
$this->set($tableAlias, $this->paginate($table, $conditions));
$this->set('tableAlias', $tableAlias);
$this->set('_serialize', [$tableAlias, 'tableAlias']);
}
/**
* Add method
*
* @return mixed Redirects on successful add, renders view otherwise.
*/
public function add()
{
$table = $this->loadModel();
$tableAlias = $table->alias();
$entity = $table->newEntity();
$this->set($tableAlias, $entity);
$this->set('tableAlias', $tableAlias);
$this->set('_serialize', [$tableAlias, 'tableAlias']);
if (!$this->request->is('post')) {
return;
}
$entity = $table->patchEntity($entity, $this->request->getData());
$entity->role = $this->request->data('role');
$singular = Inflector::singularize(Inflector::humanize($tableAlias));
if ($table->save($entity)) {
$this->Flash->success(__d('CakeDC/Users', 'The {0} has been saved', $singular));
return $this->redirect(['action' => 'index']);
}
$this->Flash->error(__d('CakeDC/Users', 'The {0} could not be saved', $singular));
}
/**
* Edit method
*
* @param string|null $id User id.
* @return mixed Redirects on successful edit, renders view otherwise.
* @throws NotFoundException When record not found.
*/
public function edit($id = null)
{
$table = $this->loadModel();
$tableAlias = $table->alias();
$entity = $table->get($id, [
'contain' => []
]);
$this->set($tableAlias, $entity);
$this->set('tableAlias', $tableAlias);
$this->set('_serialize', [$tableAlias, 'tableAlias']);
if (!$this->request->is(['patch', 'post', 'put'])) {
return;
}
$entity = $table->patchEntity($entity, $this->request->getData());
$entity->role = $this->request->data('role');
$singular = Inflector::singularize(Inflector::humanize($tableAlias));
if ($table->save($entity)) {
$this->Flash->success(__d('CakeDC/Users', 'The {0} has been saved', $singular));
return $this->redirect(['action' => 'index']);
}
$this->Flash->error(__d('CakeDC/Users', 'The {0} could not be saved', $singular));
}
}
If I change the database directly and set the field "is_superuser" to "1" the new user can log in without error. But I can't find where the problem is.
Thanks.
Check debug.log when debug is true to understand the rules evaluation and debug the issue. It looks like the logged in user (debug the user data from $this->Auth->user()
role is not matching your defined rules.
Also check the correct key for defining permissions is CakeDC/Auth.permissions
see https://github.com/CakeDC/users/blob/master/config/permissions.php#L53
I would modify the rule
[
'role' => [GROUP_SUPER_ID, GROUP_ADMIN_ID],
'prefix' => '*',
'extension' => '*',
'plugin' => '*',
'controller' => '*',
'action' => '*'
],
And change role to *
then debug the user and match the role is correct. Check first you can access the target page via this rule, then start restricting the rule to what you need.