We have recently shifted our application from http to https due to plain password logins via the API.
However, since doing so we are having real issues with Blackholes. Cake seems to black hole any 'POST' to the API function within our controller, despite
$this->Security->validatePost = false;
being set in AppController.php
We are using CakePHP version 2.1.3
Example of the code is as follows:
AppController.php:
function beforeFilter()
{
$this->Security->validatePost = false;
$this->Security->requireSecure();
}
SaleOrderController.php:
function beforeFilter()
{
parent::beforeFilter();
$this->Auth->allow('addApi'); // Allow access to the API without logging in.
}
POSTing to this URL gives back the following message:
"The request has been black-holed"
Once we can get this working (without being blackholed) we will adjust it so that only certain actions may be performed with validatePost = false. However, for now we just want to get the system working.
Note: 'GET' requests to the action work fine (are not blackholed).
Am I missing some simple configuration here or is there some deeper issue at work? The security module seems a little scant on documentation and from my google searches it looks like most people have avoided blackholing by performing the same steps I have.
Turns out the following has no effect in CakePHP 2.X:
$this->Security->enabled = false;
To disable components you need to follow this doc:
http://book.cakephp.org/2.0/en/core-libraries/components/security-component.html
My issue was related to CSRF protection which I believe may be new in CakePHP 2.X?
Anyway, All I needed to do was add the following line within my SaleOrderController beforeFilter function:
$this->Security->csrfCheck = false;
My whole BeforeFilter function is now:
function beforeFilter()
{
parent::beforeFilter();
$this->Auth->allow('addApi'); // Allow access to the API without logging in.
if (isset($this->Security) && $this->action == 'addApi') {
$this->Security->csrfCheck = false;
$this->Security->validatePost = false;
}
}
See below URL
CakePHP: Disable Security Component site wide
Disabling input elements in a CakePHP form that uses Security component and jQuery
http://life.mysiteonline.org/archives/175-Disable-the-Security-Component-in-CakePHP-only-for-Certain-Actions.html
http://book.cakephp.org/2.0/en/core-libraries/components/security-component.html
http://api.cakephp.org/class/security-component
Or try it:-
Even if you disable it in your app_controller your individual controller may have that security enabled.As my wild guess says this is what you want to do.If not let me know more about it
function beforeFilter(){
parent::beforeFilter();
if(isset($this->Security) && $this->RequestHandler->isAjax() && $this->action = 'add'){
$this->Security->enabled = false;
}
}
Related
I am trying to authorize users depending on the type of the users(i.e. student,admin,staff), and here is the code which I have written in AppController.php .
public function isAuthorized($user = null) {
// Any registered user can access public functions
if (empty($this->request->params['admin']) && empty($this->request->params["staff"])) {
return true;
}
if(isset($this->request->params["staff"])){
return (bool)($user["type"]==="staff" || $user["type"]==="admin");
}
// Only admins can access admin functions
if (isset($this->request->params['admin'])) {
return (bool)($user['type'] === 'admin');
}
// Default deny
return false;
}
After the login as "student", I typed localhost/kit-web/admin in the address bar in order to make sure that "student" has no access right to admin pages. But strangely, the webpage was redirected to localhost/kit-web/kit-web. And this caused missing Kit-webController.php error. If any user has an access right to a certain page, then everything is working fine. I am guessing that one possible reason is I have installed CakePHP using composer, so the directory configuration is different from the unzipped one. However, I have configured the location of ROOT, CAKE_CORE_INCLUDE_PATH, APP_DIR, following the cakephp tutorial.
Does anyone have any idea what is going wrong?
I have solved the problem by myself.
Reading the core source files of CakePHP, I realized that if the field "unauthorizedRedirect" is not specified, AuthComponent redirects to "/{app directory}" (i.e. $this->redirect("/{app directory}") by default. $this->redirect("/{app directory}") does not redirect the page to "/" because {app directory} is regarded as controller name. I am not sure whether this is bug or not. But I hope this helps if anyone is struggling with the same problem.
I want my users to redirect to a custom URL after they successfully register in Joomla .
I can't find any option for that !
How can I achieve this ?
If you are using Joomla!'s built-in menu to load the registration page, or getting there from the Login module there isn't a way to redirect (which is odd because you can set a redirect after login in the login module).
The best place to start would be to look at existing solutions in the "Authentication" section of the Joomla! Extension Directory. It appears there are several listed that support both the old 1.5 style sites and the new 1.7/2.5 sites.
(By the way if you are still on 1.7 you should update to the latest 2.5 as there are serious security issues in the 1.7 line.)
In your code set do the following;
$app=JFactory::getapplication();
$app->redirect('index.php?option=com_users&view=login'));
You can achieve this with a plugin (at least in Joomla 3.x - not sure how far back this will work off-hand). Key here is the onUserAfterSave event, which tells you whether the user is new or existing.
I wrote the code below some time ago, so can't recall the exact reason the redirect could not be done from within the onUserAfterSave event handler, but I think the redirect is subsequently overridden elsewhere in the core Joomla user management code if you try to do it from there, hence saving a flag in the session and checking it in a later event handler.
class PlgUserSignupRedirect extends JPlugin
{
public function onUserAfterSave($user, $isnew, $success, $msg)
{
$app = JFactory::getApplication();
// If the user isn't new we don't act
if (!$isnew) {
return false;
}
$session = JFactory::getSession();
$session->set('signupRedirect', 1);
return true;
}
function onAfterRender() {
$session = JFactory::getSession();
if ($session->get('signupRedirect')) {
JFactory::getApplication()->redirect('/my-post-signup-url');
$session->clear('signupRedirect');
}
}
}
We're currently running an app that caches pages to static html files using Zend_Cache_Backend_Static. This works really well, except that our cache is getting filled with hundreds of empty files and folders when incorrect urls are requested. Is there any way to prevent a page being cached if an Exception is being thrown? I was surprised to discover that this wasn't standard behaviour.
I've done a little digging and the ZF code that actually deals with saving out the static html pages is as follows in Zend_Cache_Frontend_Capture:
public function _flush($data) {
$id = array_pop($this->_idStack);
if ($id === null) {
Zend_Cache::throwException('use of _flush() without a start()');
}
if ($this->_extension) {
$this->save(serialize(array($data, $this->_extension)), $id, $this->_tags);
} else {
$this->save($data, $id, $this->_tags);
}
return $data;
}
This function is the output_callback for ob_start. I've tried getting hold of the response object to test for status but it doesn't seem to work inside _flush.
$response = Zend_Controller_Front::getInstance()->getResponse();
if($response->getStatus() == '200') {
// do the save as normal
}
else {
// do nothing
return false;
}
My only other thought was to test the length of $data, only caching if strlen($data) > 0 seems to work but it doesn't feel robust enough.
Update:
Unfortunately by the time we hit the ErrorController the static page has already been written to the cache, so disabling the cache at that point won't work. However it is possible to remove the page based on $_SERVER['REQUEST_URI'], which is what is used as an id when the page is first written. This line can be added to the start of errorAction in the ErrorController:
$this->_helper->cache->removePage($_SERVER['REQUEST_URI'], true);
It works nicely, but I'd prefer not to write the page in the first place!
From further experimentation the problem is not down to standard Zend Framework exceptions that cause 404s (ie. Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ROUTE, Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER, Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION) but to my custom exceptions. This is now really obvious now that I think about it, as Zend_Cache_Backend_Static needs to be initialised in the init method of an action controller. Any situation where there is no route, controller or action it won't ever be initialised anyway.
I'm throwing exceptions in existing actions where a user may be querying for a non-existent article. Therefore caching has been enabled in init and the page has been written by the time we hit postDispatch in a Front Controller Plugin (still not sure why this is the case it just is) so I can't cancel at that point. One solution then is to cancel the cache at the point of throwing the exception. The standard method of managing static page caching is using the Zend_Controller_Action_Helper_Cache action helper. I've extended this to add a cancel method like so:
<?php
class Zend_Controller_Action_Helper_PageCache extends Zend_Controller_Action_Helper_Cache {
public function cancel() {
$cache = $this->getCache(Zend_Cache_Manager::PAGECACHE);
$cache->setOption('caching', false);
$cache->getBackend('disable_caching', true);
}
}
My action controller now looks like this:
<?php
class IndexController extends Zend_Controller_Action {
private $_model;
public function init() {
$this->_model = new Model();
// using extended pageCache rather than $this->_helper->cache:
$this->_helper->pageCache(array('index'), array('indexaction'));
}
public function indexAction() {
$alias = $this->_request->getParam('article');
$article = $this->_model->getArticleByAlias($alias);
if(!$article) {
// new cancel method will disable caching
$this->_helper->pageCache->cancel();
throw new Zend_Controller_Action_Exception('Invalid article alias', 404);
}
$this->view->article = $article;
}
}
You should alter your .htaccess file RewriteRules to check for filesizes with option -s
This way if an error should occur when a page is being cached (thus producing a 0 byte file) it won't permanently be stored in the cache.
If you are using the standard ErrorController to handle 404, 500, and unhandled exceptions, and you can get a reference to your cache object from there, you could disable caching from the error handler.
In your error controller (or wherever you would like to cancel caching from), try:
$cache->setOption('caching', false);
When the save() metod of Zend_Cache_Core is called by Zend_Cache_Frontend_Capture::_flush(), it will see the caching option is set to false and it will not actually save the data to the cache and return true.
I want to turn on the debug mode for particualr controller in cakephp . Now I am doing this in config/core.php ,it working fine . But it is easy to enable /disable in controller ,we can avoid probelms with working in live sites ,otherwise the log will messed up users
its actually security critical to do anything wild like that in the core.php, it has to be and stay always 0 for ALL user frontend sites.
If you want to enable it for some admin backend action, you can do that inside the action at the very beginning with
Configure::write('debug', 2);
I'm late to the party on this one but just in case anyone else needs this
$skdebug = 0;
if ($_SERVER["REMOTE_ADDR"]== '121.75.33.244') $skdebug = 2;
Configure::write('debug', $skdebug);
I work offsite so I'm the only user on the IP, can be a pain to have to keep updating the IP when the router decides to bounce but it's a small price to pay.
It does mean debug is on for all controllers but that's not a problem.
It work for me in cakephp 3.4.
Use the below code in top of your controller in cakephp 3+:
use Cake\Core\Configure;
Then your beforeFilter() code should be something like below:
public function beforeFilter(\Cake\Event\Event $event){
parent::beforeFilter($event);
$this->loadComponent('RequestHandler');
// allow the function to public access
$this->Auth->allow(['index','logout','register','saveOrders']);
$actions = [
'saveOrders','save-orders',
];
// change the debug mode for a particular action
if (in_array($this->request->params['action'], $actions)) {
Configure::write('debug', false); // off debug mode
}
}
I have some Zend Framework apps running and it's time to add user access restrictions. I am a firm believer that you should try to avoid rolling your own security infrastructure whenever possible and so I have been trying to figure out how to use Zend_Auth and Zend_Acl to implement it, so far without success.
I have searched all over the net, and at least one book, and I can't find an example of how to string all of the parts together. I found an example of authentication here, old examples of authorization / access control here and here, and proposals for the future here, here, and here, but I don't understand ZF well enough to put it all together in the present.
What I need is this: a simple public example or tutorial that completely details [as downloadable and runnable code] how to use the current Zend Framework release (1.9.5, no "proposals" or "laboratories") to manage the authentication/authorization/access control of three users (and their passwords) in three different roles (e.g. guest, member, administrator) to protect three different controllers in the default module. The example should use as much of the current ZF library as possible. And no, this isn't homework; the stakes are higher than that :-(
If it exists somewhere I haven't found it. Any help appreciated. IMO this would be very helpful for newcomers to ZF.
Disclosure: I have a community wiki question on ZF here beause I'm trying to figure out if I'll continue with it. But I really need to get my apps running now!
Pro Zend Framework Techniques, Chapter 8 has a nice treatment of this. Most of his approach is quite similar to what I use, with the exception of the preDispatch method. When authenticating I have preDispatch redirect instead of silently dispatching to another controller. I also preserve the Url that was requested for the use of the login action.
class SitePluginAuth extends Zend_Controller_Plugin_Abstract
{
private $_auth;
private $_acl;
private $_noauthPath = '/account/log-in/';
private $_noacl = array('module' => 'default', 'controller' => 'error', 'action' => 'denied');
public function __construct($auth, $acl)
{
$this->_auth = $auth;
$this->_acl = $acl;
}
public function preDispatch($request)
{
$resource = $request->controller;
if (!$this->_acl->has($resource)) return;
$controller = $request->controller;
$action = $request->action;
$module = $request->module;
if ($this->_auth->hasIdentity()) {
$identity = $this->_auth->getIdentity();
$role = 'member';
}
else {
$role = 'guest';
}
/*
* Remember to URL encode the parameter value. Also, when you are processing the value of the
* redirect URL, make sure that it is a URL on your site or a relative URL to avoid any security
* attacks like a phishing scheme. Otherwise, a third party can target your site's login page and
* then redirect back to their site and might have access to the user's secured session.
*
* The reason I don't use the session to store the URL, is that search engine spiders can end up
* creating sessions as they hit links on your site that are secured and require login. Since they
* have no credentials, the session is created only to timeout 30 minutes later.
*/
if (!$this->_acl->isAllowed($role, $resource, $action)) {
if (!$this->_auth->hasIdentity()) {
$requestedUrl = substr($request->getRequestUri(), strlen($request->getBaseUrl())); // relative url
$loginUrl = $this->_noauthPath.'?requestedUrl='.urlencode($requestedUrl);
$redirector = Zend_Controller_Action_HelperBroker::getStaticHelper('redirector');
$redirector->gotoUrl($loginUrl);
}
else {
$request->setModuleName($this->_noacl['module']);
$request->setControllerName($this->_noacl['controller']);
$request->setActionName($this->_noacl['action']);
}
}
}
}