cakephp-tinyauth
cakephp-tinyauth copied to clipboard
auth_allow.ini not parsing route prefix
Hi Mark, when I try to use prefixed routes to allow routes in the Api prefix, it also allows the same controllers in non-prefixed routes.
ie on auth_allow.ini:
Api/Countries
This entry also allows non-prefixed Countries controller.
I cannot figure out the reason for this behavior.
Thanks in advance.
Can you Show the details? Like URLs and Controller code?
Initialize on AppController.php (non-prefixed)
$this->loadComponent('RequestHandler');
$this->loadComponent('Flash');
$this->loadComponent('FormProtection', [
'validationFailureCallback' => function (BadRequestException $exception) {
$this->Flash->error(__('Something went wrong... <strong>Please refresh the page.</strong>'), ['escape' => false]);
return $this->redirect( $this->request->referer() );
}
]);
$this->loadComponent('TinyAuth.Authentication');
$this->loadComponent('TinyAuth.Authorization');
Initialize on AppController.php (Api prefixed, inside Api folder)
$this->loadComponent('RequestHandler');
$this->loadComponent('TinyAuth.Authentication');
$this->loadComponent('TinyAuth.Authorization');
CountriesController.php (common CRUD functions) CountriesController.php on Api folder (only index function)
auth_allow.ini
Api/Countries = index
Application.php getAuthenticationService function:
if (strpos($path, '/api') === 0) {
$service->loadAuthenticator('Authentication.Jwt', [
'returnPayload' => false
]);
$service->loadAuthenticator('ApiForm');
$service->loadIdentifier('Authentication.JwtSubject', [
'resolver' => [
'className' => 'Authentication.Orm',
'finder' => 'jwt'
]
]);
$service->loadIdentifier('Password', [
'fields' => $pwd_fields,
'resolver' => [
'className' => 'Authentication.Orm',
'finder' => 'jwt'
]
]);
return $service;
}
$service->setConfig([
'unauthenticatedRedirect' => '/backoffice',
//'queryParam' => 'redirect',
]);
$service->loadAuthenticator('Authentication.Session');
$service->loadAuthenticator('Authentication.Form', [
'fields' => $form_fields,
'loginUrl' => '/backoffice',
]);
$service->loadAuthenticator('Authentication.Cookie', [
'fields' => $form_fields,
'loginUrl' => '/backoffice',
'cookie' => [
'expires' => new \DateTime('+1 week')
]
]);
$service->loadIdentifier('Password', [
'fields' => $pwd_fields,
]);
getAuthorizationService function:
$resolver = new MapResolver();
$policy = new RequestPolicy([
'includeAuthentication' => true,
]);
$resolver->map(ServerRequest::class, $policy);
return new AuthorizationService($resolver);
Let me know if you need more code or something else. Thanks!
@dereuromark, have you found anything or do you have any ideas to fix this problem? Thanks in advance
Are you able to reproduce sth similar with demo actions on the sandbox? https://github.com/dereuromark/cakephp-sandbox That would help, as once reproduced it is easy to track down and find the issue or a fix.
Ok, I'll try. Something to keep in mind is that I am using it with the Authentication and Authorization plugins.
I think I found something. In AllowTrait.php:
protected function _getAllowRule(array $params) {
$rules = $this->_getAllow($this->getConfig('allowFilePath'));
$allowDefaults = $this->_getAllowDefaultsForCurrentParams($params);
foreach ($rules as $rule) {
if ($params['plugin'] && $params['plugin'] !== $rule['plugin']) {
continue;
}
if (!empty($params['prefix']) && $params['prefix'] !== $rule['prefix']) {
continue;
}
/*
* this check is missing when the prefix key is not set in the parameter array and the prefix is set in the rule
*/
if (empty($params['prefix']) && !empty($rule['prefix'])) {
continue;
}
/* */
if ($params['controller'] !== $rule['controller']) {
continue;
}
if ($allowDefaults) {
$rule['allow'] = array_merge($rule['allow'], $allowDefaults);
}
return $rule;
}
return [
'allow' => $allowDefaults,
'deny' => [],
];
}
These are the $params
[
'controller' => 'Countries',
'pass' => [ ],
'action' => 'index',
'plugin' => null,
'_matchedRoute' => '/{controller}',
'_ext' => null,
]
And this is the returned $rule
[
'plugin' => null,
'prefix' => 'Api',
'controller' => 'Countries',
'map' => [
(int) 0 => 'index',
],
'deny' => [ ],
'allow' => [
(int) 0 => 'index',
],
]
Do u have a fix as well? That would solve the issue?
This resolves this particular scenario. Maybe we need to run some tests. Is there a scenario like plugin key or any other key is not present?
Another way is to fill missing keys in params before send to "_getAllowRule()". In AuthenticationComponent.php there is a "_prepareAuthentication()" function, maybe we can fill missing params there before calling _getAllowRule().
This is in line 99 of AuthenticationComponent.php
$rule = $this->_getAllowRule($this->_registry->getController()->getRequest()->getAttribute('params'));
change to
$params = $this->_registry->getController()->getRequest()->getAttribute('params');
if ( !isset($params['plugin']) ) {
$params['plugin'] = NULL;
}
if ( !isset($params['prefix']) ) {
$params['prefix'] = NULL;
}
$rule = $this->_getAllowRule($params);
And this for _getAllowRule()
protected function _getAllowRule(array $params) {
$rules = $this->_getAllow($this->getConfig('allowFilePath'));
$allowDefaults = $this->_getAllowDefaultsForCurrentParams($params);
foreach ($rules as $rule) {
if ( isset($params['plugin']) && !is_null($params['plugin']) ) {
if ($params['plugin'] !== $rule['plugin']) {
continue;
}
} else {
if (!empty($rule['plugin'])) {
continue;
}
}
if ( isset($params['prefix']) && !is_null($params['prefix']) ) {
if ($params['prefix'] !== $rule['prefix']) {
continue;
}
} else {
if (!empty($rule['prefix'])) {
continue;
}
}
if ($params['controller'] !== $rule['controller']) {
continue;
}
if ($allowDefaults) {
$rule['allow'] = array_merge($rule['allow'], $allowDefaults);
}
return $rule;
}
return [
'allow' => $allowDefaults,
'deny' => [],
];
}
Because same behavior for Plugin Routes such as Api.Countries = index
Are u able to make a PR with suggested change?