cakephp: $this->Auth->allow - cakephp

When I click the Enroll Now button under admissions on my navigation bar, \merry_flowers\views\students\add.ctp should display.
Instead, the login page is getting displayed.
Does anyone know on what I'm doing wrong?
The following is my app_controller.php for the project:
class AppController extends Controller {
var $components=array('Auth','Session','Cookie');
function beforeFilter(){
if (isset($this->Auth)){
$this->Auth->userModel='MerryParent';
$this->Auth->loginAction=array('controller'=>'merry_parents','action'=>'login');
//var_dump($this->data);
$this->Auth->allow('*');
$this->Auth->loginRedirect=array('controller'=>'merry_parents','action'=>'report_card');
$this->Auth->logoutRedirect=array('controller'=>'merry_parents','action'=>'register');
$this->Auth->deny('report_card');
$this->Auth->authorize='controller';
}
else
$this->Session->setFlash('Auth has not been set');
}
function isAuthorized(){
return true;
}
Any help is much appreciated.

One gotcha is if your StudentsController has a beforeFilter, you'll need to call parent::beforeFilter or that Auth setup won't happen.
I'd also note the caveat for using authorize = 'controller'; "Remember that [isAuthorized] will be checked after you have already passed the basic authentication check against the user model.". Given that you have $this->Auth->allow('*'), auth should be skipped entirely, so I'd look for a more fundamental mistake such as the beforeFilter override.
Unfortunately nothing stands out in your pasted code. Auth problems usually involve facepalm solutions in my experience :)

Related

Cakephp 3 - CRUD plugin - Use id from auth component

Currently, I'm using the CRUD v4 plugin for Cakephp 3. For the edit function in my user controller it is important that only a user itself can alter his or her credentials. I want to make this possible by inserting the user id from the authentication component. The following controller method:
public function edit($id = null){
$this->Crud->on('beforeSave', function(\Cake\Event\Event $event) {
$event->subject()->entity->id = $this->Auth->user('id');
});
return $this->Crud->execute();
}
How can I make sure I don't need to give the id through the url? The standard implementation requires the url give like this: http://domain.com/api/users/edit/1.json through PUT request. What I want to do is that a user can just fill in http://domain.com/api/users/edit.json and send a JSON body with it.
I already tried several things under which:
$id = null when the parameter is given, like in the example above. Without giving any id in the url this will throw a 404 error which is caused by the _notFound method in the FindMethodTrait.php
Use beforeFind instead of beforeSave. This doesn't work either since this isn't the appropriate method for the edit function.
Give just a random id which doesn't exist in the database. This will through a 404 error. I think this is the most significant sign (combined with point 1) that there is something wrong. Since I try to overwrite this value, the CRUD plugin doesn't allow me to do that in a way that my inserting value is just totally ignored (overwriting the $event->subject()->entity->id).
Try to access the method with PUT through http://domain.com/api/users.json. This will try to route the action to the index method.
Just a few checks: the controllerTrait is used in my AppController and the crud edit function is not disabled.
Does anyone know what I'm doing wrong here? Is this a bug?
I personally would use the controller authorize in the Auth component to prevent anyone from updating someone else's information. That way you do not have to change up the crud code. Something like this...
Add this line to config of the Auth component (which is probably in your AppController):
'authorize' => ['Controller']
Then, inside the app controller create a function called isAuthorized:
public function isAuthorized($user) {
return true;
}
Then, inside your UsersController you can override the isAuthorized function:
public function isAuthorized($user) {
// The owner of an article can edit and delete it
if (in_array($this->request->action, ['edit'])) {
$userId = (int)$this->request->params['pass'][0];
if ($user['id'] !== $userId) {
return false;
}
}
return parent::isAuthorized($user);
}

CakePHP default layout, can't pass values to default.ctp

I have one page website, on homepage(Layout/default.ctp) I have 2 forms, subscribe and contact form that are being controlled over contact controller. With $this->set('some_val', 'test'); I can set value from AppController, but not from contact controller, how can I set values from contact controller to be available in default.ctp except with sessions?
public function beforeFilter() {
parent::beforeFilter();
//pr('beforeFilter'); // i was testing is this happening or not
//exit();
$tester = 'test';
$this->set(compact('tester'));
}
and in default.ctp I just pr($this->viewVars); to make sure that I have tester value, but it is always empty.
Is this right approach how to implement several controllers in one page design?
Another question is there a place/function where I could check is current request post or not, I would like to check for each request what is it?
Thank you.
Not sure if I understand correctly, but it sounds like you might need multiple layouts:
class CarsController extends AppController
{
public function index($page)
{
/* Your logic */
if ( $page == 'other' ) {
$this->render('view', 'layout');
} else {
$this->render('view-other', 'layout-other');
}
}
}
For more information i'd suggest looking at: http://api20.cakephp.org/class/controller#method-Controllerrender
try an echo $tester; in your default, it should be available.
If the request is post, you would have data in $this->data.

Stop execution after render in beforeFilter of CakePHP

In my CakePHP 2 application i have a problem with beforeFilter.
In this thread it worked well. Because of old version of CakePHP.
In my code, If user is not authorized, I want to show him "anotherview.ctp".
I don't want to redirect visitor to another page. (because of adsense issues)
When i use "this->render" in beforeFilter, the code in my "index" action is also run.
I want to stop the execution after the last line of "beforeFilter".
When I add "exit()" to beforeFilter, it broke my code.
How can I stop execution in beforeFilter without breaking code?
class MyController extends AppController {
function beforeFilter() {
if ( $authorization == false ) {
$this->render('anotherview');
//exit();
}
}
}
function index() {
// show authorized staff
}
}
Try:
$this->response->send();
$this->_stop();
I stumbled across this thread while trying to do the same thing. The accepted answer works but omits an important detail. I'm trying to render a layout (not a view) and I had to add an additional line to prevent the original request's view from throwing errors.
Inside AppController::beforeFilter():
$this->render(FALSE, 'maintenance'); //I needed to add this
$this->response->send();
$this->_stop();
or alternatively - redirect to another view:
if ( $authorization == false ) {
$this->redirect('/users/not_authorized');
}
For CakePHP 3.5 this is what worked for me:
$event->setResult($this->render('anotherview'));
This will also enable you to use the debugger. CakePHP Debugger stopped working when I used the exit; statement.

Redirect to maintenance page in CakePHP doesn't work

I am trying to set a maintenance page so that when the site is disabled, it should appear no matter what page was requested.
I currently tried doing this with $this->cakeError():
in app_controller.php:
function beforeFilter(){
....
if($this->__get_config('maintenance_status') == 1){
$this->cakeError('maintenance', array('message' => $this->__get_config('maintenance_message')));
}
....
}
and in app_error.php:
function maintenance($message){
$this->controller->set('message', $message['message']);
($this->controller->RequestHandler->isAjax()) ? $this->_outputMessage('ajax_maintenance') : $this->_outputMessage('maintenance');
}
The problem is that a Fatal Error occurs, which says: Call to a member function isAjax() on a non-object. But I have obviously set the RequestHandler Component in app_controller.php. Moreover, I have tried calling this error from within another controller and it doesn't give me any Fatal Error.
What could be the problem? Why doesn't it recognize that I have initalized the Component?
From the CakePHP book:
Calling this method will show an error page to the user and halt any further processing in your application
I am assuming that you're calling the error in some callback in AppController.
If that is the case you may very likely be halting execution of your script before your components are instantiated. This would certainly cause your error.
Now, I think this error is a good chance to reevaluate how you're dealing with the problem. Is this really an error? You know the maintenance status is set so it's expected that the user be shown this page. It isn't an error. Furthermore, you certainly wouldn't want 10,000 messages in your log telling you that you turned maintenance on!
I think this could be better solved by utilizing some controller callbacks and a little bit of code.
I don't know what _get_config() is so I assume it is a custom user function that you can call in this callback.
We'll be using the beforeFilter() controller callback.
class AppController extends Controller {
public function beforeFilter() {
if ($this->_get_config('maintenance_status') === 1) {
$this->redirect('/maintenance');
}
}
}
Now, you can just setup a maintenance controller, attached to its own view, that will properly show your maintenance message, and won't log all those connection attempts during maintenance in your error log.
Slightly better would also be to use the Configure::read( "System.maintenance" ) or similar. (I tend to namespace my config data, System being the namespace for stuff like maintenance flags etc.)
Also, as Charles said - don't use an error page for an expected event. Errors are to show the user, and for the application to handle notifications etc, about unexpected failures. The maintenance page could simply be a view file in the /app/views/pages/ folder. Redirect to that if the config key is set to true/1.
Your approach seems to be intelligent, but you might be overdoing it a little.
I have a similar setup in a site I am currently developing and I simply use the auth component to take care of it for me.
To help out, I setup a new offline layout that I force the application to use if status of the site is 0 (offline). If the status is 0 app_controller denies access to the entire site.
$this->Auth->deny('*');
$this->layout = "offline";
Also, in this layout I have a hidden login form that appears if the user clicks the message.If user is able to authenticate (all users for now - development) access is granted to the entire site using the default template.
Check it out, it might help you out...
Click Here
Some of the code, but you can read more about it in the link above
function beforeFilter(){
// Site Offline = 0 , Site Online = 1
if($this->Configuration->get_site_status() == 1){
// Allow access to the site to all users and perform all required
// beforeFilter code
}else{
...
// If site is OFFLINE but User is logged in allow access.
// Later I will need to change it to only allow admin access if logged in as I am still developing
// Everyone else will be denied access even if they are able to authenticate
if(!$this->Auth->user() == null){
$this->layout = 'default';
$this->Auth->allow('*');
}else{
$this->layout = 'offline';
$this->Auth->deny('*');
}
...
}
}

Cakephp html2pdf auth problem

i am new with cake but i´ve somehow managed to get through so far. After i´ve figured out that html2pdf is a convienient way to produce pdf documents out of Cakephp, i´ve installed html2ps/pdf and after some minor problems it worked. So now i am coming now to the point that if i don´t modify my controllers beforeRender function like:
function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow('download','view');
}
i just see my loginpage in the pdf i´ve created. Setting within my beforeRender function the $this->Auth->allow value opens obviously erveryone the way to get a perfect pdf without being authorized. The whole controller looks like this:
<?php
class DashboardController extends AppController {
var $name = 'Dashboard';
var $uses = array('Aircrafts','Trainingplans',
'Fstds','Flights','Properties','Person');
function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow('download','view');
}
function view() {
/* set layout for print */
$this->layout = 'pdf';
/* change layout for browser */
if> (!isset($this->params['named']['print']))
$this->layout = 'dashboard';
/* aircrafts */
$this->Aircrafts->recursive = 0;
$aircrafts =$this->Aircrafts->find('all');
$this->set('aircrafts',$aircrafts);
.... and so on....
$this->set('person_properties',$person_properties);
}
function download($id = null) {
$download_link = 'dashboard/view/print:1';
// Include Component
App::import('Component', 'Pdf');
// Make instance
$Pdf = new PdfComponent();
// Invoice name (output name)
$Pdf->filename = 'dashboard-' . date("M");
// You can use download or browser here
$Pdf->output = 'download';
$Pdf->init();
// Render the view
$Pdf->process(Router::url('/', true) . $download_link);
$this->render(false);
}
}
?>
So in my opinion the $Pdf->process call get´s the data by calling more or less the view, but this process is not logged in, or in other words not authorized to get the data i want to render into the pdf. So the question is now how to get it done by not opening my application to everyone.
Best regards, cdjw
Edit:
You could do something like this:
if($this->Session->check('Auth.User')) {
// do your stuff
} else {
// do something else
}
You could check for 2 things before rendering /view:
a valid session (a user is logged in)
a valid security token that you pass from your download action as a named parameter
For the security token, just make up a long random string.
As the PDF is rendered on the same server, the token will never be known in the open and provide sufficient security.
Hope this is a working idea for you.
I had this similar issue, and this is how I handled it...
I first noticed that the process call of the PdfComponent was doing a request from the same server, so I tricked CakePHP on allowing the view only for requests being made from the server itself.. like this:
public function beforeFilter() {
if ($this->request->params['action']=='view'&&$_SERVER['SERVER_ADDR']==$_SERVER['REMOTE_ADDR']) { // for PDF access
$this->Auth->allow('view');
}
}
You should put
$this->Auth->allow('download','view');
inside AppController. rather than place where are you using now.
function beforeFilter() {
$this->Auth->allow('download','view');
....
}

Resources