Recent Changes - Search:

Cookbook

PmWiki

pmwiki.org

SwitchToSSLMode

Summary: How to force PmWiki to use SSL
Version: 2007-06-12
Prerequisites: PmWiki 2.x
Status: Beta
Maintainer: HaganFox

Questions answered by this recipe

How can I force PmWiki to use SSL?

Description

How to force Pmwiki to serve pages using SSL (HTTPS instead of HTTP).

Method 1

One way to do this is with the following in a local configuration file (near the very top of config.php would be a good place):

if (@$_SERVER['HTTPS'] != 'on' && @$_SERVER['SERVER_PORT'] != '443') {
  header("Location: https://www.example.com/pmwiki/pmwiki.php");
  exit('<html><body>
    <a href="https://www.example.com/pmwiki/pmwiki.php">Please use SSL.</a>
    </body></html>');
}
$ScriptUrl = 'https://www.example.com/pmwiki/pmwiki.php';
$PubDirUrl = 'https://www.example.com/pmwiki/pub';

How it works: If the server isn't in SSL mode (determined by checking whether or not the global variable $_SERVER['HTTPS'] is set to "on") redirect the browser to a default URL that uses SSL. If the redirection doesn't take effect for some reason, stop the script and produce a "Please switch to SSL" link that points to the default URL.

The example assumes the URL path to your wiki is pmwiki/pmwiki.php . If you're using Clean URLs, $ScriptUrl might be something else, like https://www.example.com/wiki or even https://www.example.com . If you are not sure what $ScriptUrl should be, put {$ScriptUrl} in a wikipage and see what it is now.

Method 2

Here's another possible solution. This time where only actions where passwords are likely to be passed are sent via SSL:

## Switch to SSL mode when password would be sent in the clear.
$SSLActions = array(
  '1'=>'login', 'edit', 'post', 'postattr', 'attr', 'upload', 'loginadmin');
$SSLActions = array_flip($SSLActions);
if ($SSLActions[$action])
{
  $ScriptUrl = 'https://www.example.com/pmwiki/pmwiki.php';
  $PubDirUrl = 'https://www.example.com/pmwiki/pub';

  if (@$_SERVER['HTTPS'] == 'on'
    || @$_SERVER['SERVER_PORT'] == '443')
  {
    # Copy all GET request parameters and avoid
    # a problem with empty filename on upload page.
    $getparms = array();
    reset($_GET);
    while(list($name,$value) = each($_GET))
      if(!empty($value) && $name != 'n')
        $getparms[$name] = $name."=".urlencode($value);
    Redirect($pagename,'$PageUrl?'.implode("?",$getparms));
  }
} else {
  $ScriptUrl = 'http://www.example.com/pmwiki/pmwiki.php';
  $PubDirUrl = 'http://www.example.com/pmwiki/pub';
}

The example assumes there are not read-protected pages, since any 'read' passwords entered to view a page would be sent via a non-SSL connection.

Method 3

This is the method I am using. --RyanVarick, November 2010.

I want to enable SSL for any admin action, the entire admin session (ie when I am logged in), all read-protected pages (which redirect to the login form), and any page edit (anonymous or otherwise). To do this, I make a list of things I should be in SSL mode for, compare this against PmWiki's $UrlBase variable, and reload the page if there is a mismatch. Finally, I set the base PmWiki URL variables with the appropriate SSL prefix.

Note that this solution was designed for a wiki that uses only uses AuthUser. It was not tested for page- or group-level passwords.

##
## Force SSL mode for certain conditions
##

# Force SSL for all admin actions
$ssl_actions = array();
foreach($HandleAuth as $key => $value)
{
  if($value == 'admin') array_push($ssl_actions, $key);
}

# Force SSL for a few additional actions
array_push($ssl_actions, 'login');
array_push($ssl_actions, 'edit');

# Force SSL for any read-protected page and the entire admin session
if(PageVar($pagename, '$PasswdEdit') || $AuthId)
{
  array_push($ssl_actions, $action);
}

# Reload the page if the current SSL mode does not match the desired SSL mode
$desired_url_scheme = 'http';
if(in_array($action, $ssl_actions))
{
  $desired_url_scheme = 'https';
}
$http = $desired_url_scheme . '://';

if($UrlScheme != $desired_url_scheme)
{
  $url = $http . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];
  Redirect($pagename, $urlfmt='$url');
}

# Set PmWiki paths according to the SSL mode
$ScriptUrl    = $http . 'path/to/pmwiki.php';
$PubDirUrl    = $http . 'path/to/pub';
$UploadUrlFmt = $http . 'path/to/uploads';

Notes

If someone has a more reliable way for a PHP script to detect SSL mode, please share it!

For versions of PmWiki after 2.2.0-beta18, one can do the equivalent of

if (@$_SERVER['HTTPS'] != 'on' && @$_SERVER['SERVER_PORT'] != '443') {

with

if ($UrlScheme != 'https') {

or

if ($UrlScheme == 'http') {

With the following lines in config.php the values for $ScriptUrl and $PubDirUrl will adjust automatically, so a wiki will adapt and work properly whether SSL is on or not.

##  $ScriptUrl is the preferred URL for accessing wiki pages
##  $PubDirUrl is the URL for the pub directory.
$ScriptUrl = $UrlScheme.'://www.example.com/pmwiki/pmwiki.php';
$PubDirUrl = $UrlScheme.'://www.example.com/pmwiki/pub';

For versions of PmWiki prior to 2.2.0-beta18 you can use

##  $ScriptUrl is the preferred URL for accessing wiki pages
##  $PubDirUrl is the URL for the pub directory.
if (@$_SERVER["HTTPS"] == 'on' || @$_SERVER['SERVER_PORT'] == '443') {
  $ScriptUrl = 'https://www.example.com/pmwiki/pmwiki.php';
  $PubDirUrl = 'https://www.example.com/pmwiki/pub';
} else {
  $ScriptUrl = 'http://www.example.com/pmwiki/pmwiki.php';
  $PubDirUrl = 'http://www.example.com/pmwiki/pub';
}

This example is merely showing "SSL versus non-SSL" values for $ScriptUrl and $PubDirUrl. Your site may use URLs that look different from these or possibly different from each other, even to the point of changing the domain for SSL. The point is that one URL is HTTP and the other is HTTPS.


I use the config.php code below to automatically enable SSL as needed based on page actions or page name. Tested with PmWiki 2.2.0-beta63 with standard URLs, please see SwitchToSSLMode-Talk for more including limitations. --jtankers

##  Set URL to http or https,
##  Open Source 2007/09/13pm jtankers/PmWiki 2.2.0-beta63
function ChangeUrlScheme($urlscheme) { 
  $url = array();
  $query = '';
  reset($_GET);
  while(list($name,$value) = each($_GET)) {
    if (!empty($value)) {
      $url[$name] = $name."=".urlencode($value);
      $query = '?';
    }
  }
  header("Location: ".$urlscheme."://".$_SERVER['HTTP_HOST']
   .$_SERVER['PHP_SELF'].$query.implode("&",$url));
  exit;
}
##  Enable SSL for security actions and group or page names containing
##  key words
##  Open Source 2007/09/13pm2 jtankers/PmWiki 2.2.0-beta63.  
##  Limitations: SSL is not enabled for automatic login on unauthorized
##  page actions unless page action is included in $my_ssl_actions,
##  or group.page name contains $my_secure_keyword
$my_secure_domain = 'www.wiki1.net';
$my_secure_keyword = 'Secure';
$my_secure_pageactions =
  'admin,analyze,attr,crypt,diag,login,loginadmin,postattr,source,webadmin';
if (substr_count($_SERVER['HTTP_HOST'], $my_secure_domain)) { 
  if ( substr_count($my_secure_pageactions, $action) 
    || substr_count($pagename, $my_secure_keyword) 
    || substr_count($pagename, 'SiteAdmin') 
  ) {
    if (@$_SERVER['SERVER_PORT'] != '443') ChangeUrlScheme('https');
  } else {
    if (@$_SERVER['SERVER_PORT'] == '443') ChangeUrlScheme('http');
  }
}

Farms

With the following in farmconfig.php the wikis in a farm will adapt according to whether SSL is on or not.

##  $FarmPubDirUrl is the URL for the farm-wide pub directory.
$FarmPubDirUrl = $UrlScheme.'://www.example.com/path/to/the/farm's/pub';

or, in some farms,

##  $FarmPubDirUrl is the URL for the farm-wide pub directory.
$FarmPubDirUrl =
  $UrlScheme.'://'.$_SERVER['HTTP_HOST'].'/path/to/the/farm's/pub';

Finally, here's an alternative that may work on more servers (and older versions of PmWiki).

##  $FarmPubDirUrl is the URL for the farm-wide pub directory.
if (@$_SERVER["HTTPS"] == 'on' || @$_SERVER['SERVER_PORT'] == '443') {
  $FarmPubDirUrl = 'https://www.example.com/path/to/the/farm's/pub';
} else {
  $FarmPubDirUrl = 'http://www.example.com/path/to/the/farm's/pub';
}

Why not always use SSL?

From a posting by Pm :Note also that serving content through SSL can significantly increase server loads. It's often a good idea to use SSL judiciously--to only use SSL on those pages that really need to be protected in transit. This is also why commercial sites such as Amazon don't use SSL for the entire session, but only for those portions where sensitive personal information such as credit card numbers or addresses are being transmitted over the wires.

Release Notes

  • 2006-11-16 - Initial release
  • 2007-01-09 - Incremental improvement
  • 2007-04-29 - Additions and corrections
  • 2007-07-12 - Incremental improvement

Comments

See Discussion at SwitchToSSLMode-Talk

See Also

Contributors

User notes? : If you use, used or reviewed this recipe, you can add your name. These statistics appear in the Cookbook listings and will help newcomers browsing through the wiki.

Edit - History - Print - Recent Changes - Search
Page last modified on September 10, 2011, at 11:42 AM