installation instructions. Author: BCG Version: 1.0.5 Author URI: http://www.kerrins.co.uk/ * Release Notes Version 1.1 improved regular expression in as_ob_handler() for adding absolute hrefs more redirection bugfixes for shared ssl, changes to common functions Version 1.0 new feature: full support for WordPress 2.2+, removed reference to legacy code new feature: debug and reset modes for troubleshooting - do not leave enabled new feature: support for WordPress MU, but only with Private SSL new feature: secure additional custom pages defined on the config page new feature: if options are not set, inserts default values into database new feature: user can decide where you want Admin SSL's options page removed short tags from admin-ssl-config.php in line with WP plugins code of practice configuration page no longer allows non-HTTPS shared URLs to be saved more bugfixes to redirection, significant code enhancements and commenting Version 0.72 redirection bugfixes and code enhancements, improved force SSL login feature Version 0.71 full legacy version (0.64) added (realised it was incomplete!) filtering $location in wp_redirect() to ensure redirection to secure URL bugfixes for creating siteurl cookie for use in Shared SSL setups WordPress compliant readme added, with screenhots Version 0.70 support for both WP 2.5 and WP pre-2.5 using WP options and configuration page for Shared SSL code cleanup and commenting, removing all unnecessary functions Version 0.67 - removing unnecessary overloaded functions Version 0.66 - updated to work with WP 2.5 Version 0.65 - securing /wp-content/ pages * Development History admin-ssl 0.64 by Haris (haris.tv) secure-admin 0.2 by Ryan Boren $Id: admin-ssl.php 1.0.4 2008-05-19 17:25:10Z bcg $ */ // // if you are experiencing problems, set this to 'true' and messages will be logged // in the Admin SSL directory (usually /wp-content/plugins/admin-ssl/debug.log // define("DEBUG",false); // // if this is 'true' then the database will be updated with the default options - use if // you cannot access admin-ssl-reset.php after setting wrong Shared SSL settings // you MUST change back to false after resetting, or you will not be able to enable SSL // define("RESET",false); /* * * * * * * * * DO NOT EDIT BELOW THIS LINE - USE THE CONFIG PAGE TO CHANGE SETTINGS * * * * * * * * */ // // requires $wp_version check - this plugin WILL BREAK earlier versions of WordPress and WPMU // if(isset($wp_version) && strpos($wp_version,"wordpress-mu") === false && $wp_version >= 2.2) { // // // DEBUG MODE // // // // log debug messages to plugin operating directory // function as_log($msg) { global $path,$slash; if($path && $slash && DEBUG) error_log(preg_replace('/\t/',"",$msg)."\n\n",3,$path.$slash."debug.log"); } // // display message on admin pages if debug or reset are enabled // function as_warning() { global $path,$slash; if(DEBUG) echo('

Admin SSL is currently debugging to: '.$path.$slash.'debug.log

'); if(RESET) echo('

Admin SSL is currently in reset mode - you will not be able to secure your site with SSL until you disable reset mode.

'); } // // // GENERAL PURPOSE FUNCTIONS // // // // shorthands for lazy people // function host(){ # returns HTTP_HOST with any port numbers removed return(preg_replace('/:.+$/',"",$_SERVER["HTTP_HOST"])); } function is_https(){ # return true or false, HTTPS enabled return("on" !== $_SERVER["HTTPS"] ? false : true); } function redirect_to(){ # return WordPress' redirect_to return(isset($_REQUEST["redirect_to"]) ? $_REQUEST["redirect_to"] : ""); } function req_uri(){ # return server request uri return($_SERVER["REQUEST_URI"]); } function scheme($use_https){ # return scheme based on test value return(($use_https ? "https" : "http")."://"); } function user_can($what){ # checks if function exists before calling it return(function_exists("current_user_can") ? current_user_can($what) : false); } // // return scheme based on whether or not SSL is enabled // // // safe redirect function - don't want to use wp_redirect() // function as_redirect($location) { header("location: $location"); exit; } // // // OPERATING DIRECTORY AND WPMU DETECTION // // // // get operating directory and log environment variables // $slash = strpos(__FILE__,"/") === false ? "\\" : "/"; $path = str_replace($slash."admin-ssl.php","",__FILE__); $dir = substr($path,strrpos($path,$slash)+1); as_log("### ADMIN SSL BEGINS ###"); as_log("HTTP Host: ".host()." Request URI: ".req_uri()." Redirect to: ".redirect_to()." HTTPS: ".(is_https() ? "Yes" : "No")." Found admin-ssl.php in - path: $path - directory: $dir"); // // if operating directory is mu-plugins, get the name of admin-ssl directory // $plugins_dir = "plugins"; $config_page = $wp_version < 2.5 ? "admin-ssl-config-old.php" : "admin-ssl-config.php"; if($dir === "mu-plugins") { $d_mu_plugins = dir($path); $tmp = ""; // // loop through the main plugins directory // while(false !== ($plugin_dir = $d_mu_plugins->read())) { if($plugin_dir !== "." && $plugin_dir !== "..") { // // build the path to each entry - if it is a subfolder, open it // $plugin_path = $path.$slash.$plugin_dir; if(is_dir($plugin_path)) { $d_plugin = dir($plugin_path); // // loop through each item in this subfolder, searching for $config_page // while(false !== ($entry = $d_plugin->read())) { if(is_file($plugin_path.$slash.$entry) && $entry === $config_page) { $tmp = $plugin_dir; break(2); } } } } } // // if the loop finds the config file it saves the directory as $tmp and breaks the loop // if($tmp) { $dir = $tmp; $plugins_dir = "mu-plugins"; $config_parent = "wpmu-admin.php"; as_log("Using WPMU - Admin SSL directory changed to: $dir"); } } // // function returns true if WPMU has been detected // function is_wpmu() { global $plugins_dir; return($plugins_dir === "mu-plugins" ? true : false); } // // log variables just defined // as_log("Plugins directory: $plugins_dir Config page: $config_page Is WPMU: ".(is_wpmu() ? "Yes" : "No")); // // // GET (OR SET DEFAULT) OPTIONS // // // // get, update or insert default Admin SSL database options // function as_option($action,$name,$value=false) { // // add the prefix for Admin SSL options // $name = "admin_ssl_$name"; if($action === "get") { // // get the existing option from the database, or set to false if resetting options // $option = RESET ? false : (is_wpmu() ? get_site_option($name) : get_option($name)); if($option === false && $value !== false) { is_wpmu() ? update_site_option($name,$value) : update_option($name,$value); return($value); } else return($option); } // // when updating ensure that the user has enough privileges to do so // elseif($action === "update" && user_can("manage_options")) return(is_wpmu() ? update_site_option($name,$value) : update_option($name,$value)); } // // get (or set default) options from the database // $use_ssl = as_option("get","use_ssl","0") === "1" ? true : false; $use_shared = as_option("get","use_shared","0") === "1" && $use_ssl && !is_wpmu() ? true : false; $shared_url = as_option("get","shared_url",""); $additional_urls = as_option("get","additional_urls","wp-comments-post.php"); $secure_users_only = as_option("get","secure_users_only","0") === "1" ? true : false; if(!isset($config_parent)) $config_parent = as_option("get","config_parent","plugins.php"); // // build secure site url // $shared_url = rtrim(str_replace("wp-admin","",$shared_url),"/"); # remove wp-admin and trailing slash $secure_url = $use_shared ? $shared_url : preg_replace("|^https?://|",scheme($use_ssl),get_option("siteurl")); $secure_url = rtrim(trim($secure_url),"/"); # remove any trailing slashes // // log plugin options // as_log("Use SSL: ".($use_ssl ? "Yes" : "No")." Use shared: ".($use_shared ? "Yes" : "No")." Secure URL: $secure_url Additional urls:\n".print_r($additional_urls,true)." Secure users only: ".($secure_users_only ? "Yes" : "No")." Config parent: $config_parent"); // // // WORDPRESS HOOKS - CHECKING HTTP/HTTPS // // // // checks if the uri matches any of the default or additional urls // function as_secure_uris($separate=false) { global $additional_urls; // // build arrays of default and additional urls to secure // $tmp1 = array(); $tmp1[] = "wp-login.php"; $tmp1[] = "wp-admin/profile.php"; if(is_https()) # these need securing whenever HTTPS is enabled { $tmp1[] = "wp-admin/css/"; # admin css files $tmp1[] = "wp-admin/images/"; # admin images $tmp1[] = "wp-admin/js/"; # admin javascript files $tmp1[] = "wp-admin/admin-ajax.php"; # admin ajax scripts $tmp1[] = "wp-admin/rtl.css"; # random admin css file $tmp1[] = "wp-admin/wp-admin.css"; # main admin css file $tmp1[] = "wp-content/"; # secures themes, plugins and uploads $tmp1[] = "wp-includes/"; # secures WP javascript files etc } $tmp2 = explode("\n",$additional_urls); // // clean both arrays so they match properly later // if(!function_exists("as_trim")){ function as_trim(&$v){ $v = trim($v); } } array_walk($tmp1,"as_trim"); array_walk($tmp2,"as_trim"); // // remove any empty values from the additional urls array // foreach($tmp2 as $k => $v) if($v == "") unset($tmp2[$k]); // // return secure uris // if($separate) return(array("default" => $tmp1,"additional" => $tmp2)); else return(array_merge($tmp1,$tmp2)); } // // runs on WordPress init, performs all sorts of clever redirecting // function as_init() { global $use_ssl,$secure_url,$shared_url; // // start output buffering to secure all links // if($use_ssl) ob_start("as_ob_handler"); // // check if any of the secure uris matches the current request uri // $match = false; foreach(as_secure_uris() as $uri) if(strpos(req_uri(),$uri) !== false) $match = true; // // for redirection between Shared SSL URL and site URL we need the bit of the URL // AFTER either $secure_url or siteurl - as an example: // to redirect from http://your_blog.com/wp-admin/profile.php // to https://some_host.com/~username/wp-admin/profile.php // we need to get /wp-admin/profile.php from siteurl as the path to add to $secure_url // $url_info = parse_url(is_https() ? $secure_url : get_option("siteurl")); $url_path_len = strlen($url_info["path"]); $path = substr(req_uri(),$url_path_len); as_log("as_init()\nURL path: $path"); // // redirect as necessary - secure both admin pages and wp-login.php // or, if $use_ssl is false, un-secure those pages // also ensures the right HTTP_HOST is being used, if changing between // Private and Shared SSL // if($match) { as_log("as_init()\nMatched url"); // // parse the url we need to redirect to // $url = parse_url($use_ssl ? $secure_url : get_option("siteurl")); if((!is_https() && $use_ssl) || (is_https() && !$use_ssl) || host() !== $url["host"]) { # build the url, ignoring path info before the first instance of 'wp-' $location = scheme($use_ssl).$url["host"].rtrim($url["path"],"/").$path; as_log("as_init()\nRedirecting to: $location"); as_redirect($location); } elseif($use_ssl && is_https() && redirect_to()) { # when switching between URLS need to remove path info before wp-admin $wp_admin = strpos(redirect_to(),"wp-admin"); if($wp_admin !== 0) $_REQUEST["redirect_to"] = substr(redirect_to(),$wp_admin); } } elseif(is_https()) # if it doesn't match, and the page is secured, de-secure it { as_log("as_init()\nDid not match url and it's secure, so de-secure it"); $location = get_option("siteurl").$path; as_log("as_init()\nRedirecting to: $location"); as_redirect($location); } } // // overrides check_admin_referer() in /wp-includes/pluggable.php to use $secure_url, // but only if wp-admin/ is in $secure_uris // if(!function_exists("check_admin_referer")): function check_admin_referer($action=-1,$query_arg="_wpnonce"){ global $secure_url; $secure_uris = as_secure_uris(); $adminurl = strtolower(in_array("wp-admin",$secure_uris) || in_array("wp-admin/",$secure_uris) ? $secure_url : get_option("siteurl"))."/wp-admin"; $referer = strtolower(wp_get_referer()); $result = wp_verify_nonce($_REQUEST[$query_arg], $action); if(!$result && !(-1 == $action && strpos($referer, $adminurl) !== false)){ wp_nonce_ays($action); die(); } do_action("check_admin_referer",$action,$result); return $result; }endif; // // output buffer handler to replace HTTP urls with HTTPS urls // function as_ob_handler($buffer) { global $secure_url,$secure_users_only; // // build site urls and get secure uris // $siteurl = get_option("siteurl")."/"; $home = get_option("home")."/"; $secure = $secure_url."/"; $secure_uris = as_secure_uris(true); // // on admin side, links are not absolute but relative - change this // if(is_admin()) { $pattern = "/href=['\"]((?