TIP: Use Markdown or, <pre> for multi line code blocks / <code> for inline code.
These forums are read-only and for archival purposes only!
Please join our new forums at discourse.kohanaframework.org
HTTPS for specific controllers [SOLVED]
  • I'm about to deploy a Kohana 2.3.4 application and need to force HTTPS protocol for specific controllers (e.g. login, account). I've searched around and tried various solutions, including the Require SSL Module and none seem to work pefectly. The Require SSL module seems to go into an infinite loop. Any suggestions or examples would be greatly appreciated. I will write up the various solutios in the Wiki :)

    The closest I have come to making this work is using a combination of the following:

    1) Changing the protocol in each of the required controllers (this fixes the links, images and css):

    Kohana::config_set('core.site_protocol', 'https');
    

    2) Forcing the redirect in .htaccess.

    This seems to work, but the .htaccess rewrite puts the index.php back in the url due to using {REQUEST_URI}

    Here is my current .htaccess file:

    # Turn on URL rewriting
    RewriteEngine On
    
    # Installation directory
    RewriteBase /
    
    # Protect application and system files from being viewed
    RewriteRule ^(application|modules|docs|system) - [F,L]
    
    # Allow any files or directories that exist to be displayed directly
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    
    # Rewrite all other URLs to index.php/URL
    RewriteRule .* index.php/$0 [PT,L]
    
    #Redirect specific controllers to HTTPS
    #RewriteCond %{HTTPS} off
    #RewriteRule (login|account|user) https://%{HTTP_HOST}%{REQUEST_URI}
    
  • Untested:

    RewriteCond $1 ^(login|account|user)
    RewriteCond %{HTTPS} off
    RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [L,R]

    Edit: you might want to move this rule ahead of the others.
  • Also, you can save some trouble and set the protocol dynamically in your config.php:

    $config['site_protocol'] = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http';
  • I find it more transparent to force the protocol in the code rather than in .htaccess. I extended the url helper and added this method:


    class url extends url_Core {

    public static function force_ssl($to_ssl = true)
    {
    if ($to_ssl)
    {
    // force https if not already
    if (! isset($_SERVER["HTTPS"]))
    {
    url::redirect(url::site(url::current(), 'https'));
    }
    }
    else
    {
    // force http if not already
    if (isset($_SERVER["HTTPS"]))
    {
    url::redirect(url::site(url::current(), 'http'));
    }
    }
    }

    }

    Then in your controller (or parent controller) that requires ssl:

    url::force_ssl();


    And those that should be http protocol:

    url::force_ssl(false);
  • @rick: Your .htaccess worked great! Thanks! Your url helper solution looks interesting, however, my server does not seem to have the $_SERVER["HTTPS"] environment variable set. Using the url helper would probably work better since now all links from the secured pages are converted to https, thus if a user clicks a links back to the homepage from the login page the homepage uses the https protocol instead of http.

  • My final solution was as follows:

    1) Use the .htaccess provided by @rick above:

    RewriteCond $1 ^(login|account|user)
    RewriteCond %{HTTPS} off
    RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [L,R] 
    

    2) Add the following to the Website_Controller (extends Template_Controller) protected $ssl = FALSE; // default ssl to false for all controllers

    if ($this->ssl) { Kohana::config_set('core.site_protocol', 'https'); }
    

    3) Add the following to the constructor of each controller that requires ssl: $this->ssl = 1;

    4) Create a MY_html to extend the html::anchor() method to force http for all links by default. This fixes the issue of navigation links on ssl pages pointing to https. Linking back to an ssl page is not an issue since Apache rewrites the url to https via the .htaccess above.

    public static function anchor($uri, $title = NULL, $attributes = NULL, $protocol = 'http', $escape_title = FALSE)
    

    The only potential issue now is how to restrict people from going to https versions of the pages that don't require ssl, to avoid duplicate content issues.

  • I have a better solution on this... having to do only on the .htaccess here is the example:

    
    # Turn on URL rewriting
    RewriteEngine On
    
    # Installation directory
    RewriteBase /
    
    # Protect application and system files from being viewed
    RewriteRule ^(application|modules|system) - [F,L]
    
    # Allow any files or directories that exist to be displayed directly
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    
    # Rewrite all other URLs to index.php/URL
    RewriteRule .* index.php/$0 [PT,L]
    rewritecond %{http_host} ^domain.com [nc]
    rewriterule ^(.*)$ http://www.domain.com/$1 [r=301,nc] 
    
    #Redirect http to https on the master/login page
    RewriteCond %{SERVER_PORT} 80 
    RewriteCond %{REQUEST_URI} master/login 
    RewriteRule ^(.*)$ https://www.domain.com/master/login/ [R,L]
    
    #Redirect http to https on the client page
    RewriteCond %{SERVER_PORT} 80 
    RewriteCond %{REQUEST_URI} client 
    RewriteRule ^(.*)$ https://www.domain.com/client/ [R,L]
    
    

    cheers!!!

  • @h4ck3r5: I tried implementing your solution and it would not work for me. There seems to be an issue with the following lines:

    rewritecond %{http_host} ^domain.com [nc]
    rewriterule ^(.*)$ http://www.domain.com/$1 [r=301,nc] 
    
  • I like to create a config file for this type of thing called "secure_pages.php" which contains an array of controllers/methods that get forced to ssl, for example:

    $config['controllers'] = array(
                    "contactus",
                    "cart/checkout",
                    "cart/orderconfirmation",
                    "account/login",
                    "account/register",
                    "account/edit",
                    "account/update"
                );
    

    Then in my base controller I have a check that checks the controller name and method against the url to see if it needs to redirect to https. Saves me from having to put redirect code in any specific controllers. You can also have your base controller force all other pages back to non ssl pages using this method.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion