I have developed a cakephp site that should use ssl for all pages. It works as expected except when I use redirect in a controller it redirects to http: //subdomain.domain.com not https: //subdomain.domain.com/controller/action.
I have solved this by creating a virtual host for port 80 pointing to the cakephp application and added these rewrite rules in .htaccess
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [L]
This catches this situation and redirect to https but this gives unnecessary extra traffic to the server.
The cause for this extra traffic is the redirect function as it generates wrong urls. I have looked into the redirect function and it calls router::url to create the actual url. However I am not able to figure out how or where to instruct the router to use https not http.
Tim
I'm taking a bit of a guess, but I suspect it is this very RewriteRule that's messing things up.
You should be "redirecting" not "rewriting". Cake's generated links are usually relative to the root, so don't specify a protocol unless you pass "true" as the second parameter.
I also have apache listening on both 80 and 443 so that I can at least respond to incorrect requests.
This is the code I have in my AppController class to do the same thing:
function beforeFilter() {
parent::beforeFilter();
$this->_setupSecurity();
}
function _setupSecurity() {
$this->Security->blackHoleCallback = '_badRequest';
if(Configure::read('forceSSL')) {
$this->Security->requireSecure('*');
}
}
/**
* The main SecurityComponent callback.
* Handles both missing SSL problems and general bad requests.
*/
function _badRequest() {
if(Configure::read('forceSSL') && !$this->RequestHandler->isSSL()) {
$this->_forceSSL();
} else {
$this->cakeError('error400');
}
exit;
}
/**
* Redirect to the same page, but with the https protocol and exit.
*/
function _forceSSL() {
$this->redirect('https://' . env('SERVER_NAME') . $this->here);
exit;
}
I also have my own config 'forceSSL' option in bootstrap.php for turning this on and off depending on the environment, so that needs to be set to true for the above to work.
I found the error it was a misconfiguration of Apache.
Trying out Jamies solution, the site ended up in a redirect loop, because RequestHandler->isSSL() returned false even if the request was https. I then discovered that the $_SERVER['https'] was not set and the $_SERVER['port'] was 80, not 443 as expected.
At that point I have placed my ssl directives in sites-available/default,
SSLEngine on
SSLCertificateFile [path to cert file]
SSLCertificateKeyFile [path to keyfile]
Moving the ssl directives to the virtual host for the subdomain resolved the issue, with redirect loops.
Actually is also solved my initial problem because the method Router::url checks for $_SERVER['https'] if set it generates a url that starts with https: otherwise just http:
I have tested both Jameies solution and my own with rewrite rules in .htaccess and they both work as expected after the fix.
Tim
Its example is already mentioned in the CookBook
http://book.cakephp.org/2.0/en/core-libraries/components/security-component.html#usage
class AppController extends Controller {
// Add security component
public $components = array('Security');
public function beforeFilter() {
$this->Security->blackHoleCallback = 'forceSSL';
$this->Security->requireSecure();
}
// Add this function in your AppController
public function forceSSL() {
return $this->redirect('https://' . env('SERVER_NAME') . $this->here);
}
}