hckr.fyi // thoughts

PHP, WordPress, and Shibboleth Serving Private Posts

by Michael Szul on

If I had to rank programming languages by favorites, you can rest assured that PHP is at the bottom of my list. Most everything about the language and culture runs counter to what I enjoy.

Despite this, I am able to work within the language. I did so at Digimax Development when I needed to make improvements to a client's vacation package application, and did so again last week.

Shibboleth is an authentication service that many universities are starting to use, and it integrates well with Apache on Linux servers. Most of the configuration is done in the Shibboleth XML files, while additional changes are added to the vhost.conf or .htaccess files of the web site or application that needs to use Shibboleth.

Shibboleth can work with WordPress. In fact, there is a plugin that can get most things working outside of the box. The problem with this plugin, and the general setup of most WordPress instances is that it relies on the Location and LocationMatch directives of Apache. What if content needs to be served differently, but doesn't rely on location or URL structure to specify this difference?

For example, what if privately published pages need to be inaccessible to the outside world, but accessible within an organization? If WordPress is set up to allow subscriber access to private pages, how would you ensure a lazy session and redirect to Shibboleth for authentication?

One fork and some PHP hacking later and we have a solution:

function shibboleth_private_status_redirect() {
             if(shibboleth_get_option('shibboleth_private_redirect')) {
                     $arr = get_post_types();
                     if(shibboleth_get_option('shibboleth_private_posttypes')) {
                             $arr = array_map('trim', explode(',', shibboleth_get_option('shibboleth_private_posttypes')));
                     }
                     $pg = get_page_by_path(basename(untrailingslashit($_SERVER['REQUEST_URI'])), OBJECT, $arr);
                     if($pg) {
                             $status = get_post_status($pg->ID);
                             if("private" == $status && !is_user_logged_in()) {
                                     $target = "/wp-login.php";
                                     $target = add_query_arg("action", "shibboleth", $target);
                                     $target = add_query_arg("redirect_to", urlencode($_SERVER["REQUEST_URI"]), $target);
                                     wp_safe_redirect($target);
                                     exit();
                             }
                     }
             }
     }
    
    add_action('get_header', 'shibboleth_private_status_redirect');
    

We added options to the shibboleth admin for allowing private post types to authenticate via Shibboleth, while also allowing for a comma delimited list of post types to be used for granular control (in case you wanted private pages to force authentication, but private blog posts to be inaccessible). Ideally, the comma delimited list would be replaced by a checkbox list, but we'll leave that for a future pull request.

Pull request you say? Yes, the Shibboleth plugin is available on GitHub, and so is my fork of the project with the private post type addition.