michaelryanmcneill / shibboleth

Shibboleth plugin for WordPress
https://wordpress.org/plugins/shibboleth/
19 stars 11 forks source link

redirect_to attribute not working in Shibboleth 2.0.2 #32

Closed jbarlow1 closed 6 years ago

jbarlow1 commented 6 years ago

I upgraded the Shibboleth plugin to version 2.0.2 and it doesn’t seem to honor the redirect_to attribute anymore. The code below is at the top of the page.php template. Selected pages on the site require a Shibboleth login, and this code checks to see if the current page requires the login. The login piece works, but the user is not returned to the page that initiated the login. The user is instead directed to the wp-login page. This works fine in v1.8.1, which is why I suspected there was a change in v2. The code in part is as follows:

$prot1 = get_field('level_1_protected_pages', 'option');

if($prot1) {
    foreach($prot1 as $page_id) {
        if($page_id['page'] === $post->ID) {
            if (!shibboleth_session_active()) {
                header('Location: ' . home_url() . '/wp-login.php?redirect_to=' . get_the_permalink($post->ID) . '&reauth=1&action=shibboleth');
            }
            else {
                $emp_id = $_SERVER['HTTP_****'];
                $emp_cat = $_SERVER['HTTP_AFFILIATION'];

                //test if student but not employee
                if (strpos($emp_cat, 'student') !== false && strpos($emp_cat, 'employee') === false) {
                    header('Location: ' . home_url() . '/access-denied');
                }
            }
        }
    }
}
jbarlow1 commented 6 years ago

Can anyone assist with this issue? Thank you.

jrchamp commented 6 years ago

Hmm. Instead of trying to build the header redirect by hand, let's try using some code from shibboleth_authenticate():

if ( !shibboleth_session_active() ) {
    $initiator_url = shibboleth_session_initiator_url( get_the_permalink($post->ID) );
    wp_redirect( $initiator_url );
    exit;
}

My guess is that it has something to do with the reauth=1 parameter, but it could also be related there no being an exit; to prevent further code execution. Either way, this should be a bit cleaner.

jbarlow1 commented 6 years ago

I tried this and I get stuck in a loop on the SSO page.

jrchamp commented 6 years ago

It should only be triggering that code once and then you should have a session, which should cause shibboleth_session_active() to return true. There are two pages that are probably available for directly checking your Shibboleth status and to log in, which are typically found at /Shibboleth.sso/Session and /Shibboleth.sso/Login. When you start, the Session page should say "A valid session was not found." and the Login page should bounce you through the IdP and back to the home page. At that point, the Session page should show your session information and an attribute list. shibboleth_session_active() should definitely return true if there is an active session, so you should see the restricted page or be sent to the access denied page.

To be stuck in a loop on the SSO page, I'm guessing that the shibboleth_session_active() function is returning false because your $_SERVER variables are not what is expected. The code expects $_SERVER['Shib-Session-ID'] or an underscored version, possibly prefixed with "REDIRECT_", so if it's failing that, it's not one of the four values allowed by default.

Please let me know what you find so we can determine how to proceed.

jbarlow1 commented 6 years ago

I did not see the $_SERVER['Shib-Session-ID'] listed. I changed the code to the following and it seems to work now. Do you see any concerns with this change? I wasn't sure if merely checking for an employee ID would cause issues.

if ( !$_SERVER['HTTP_EMPID'] ) {
    $initiator_url = shibboleth_session_initiator_url( get_the_permalink($post->ID) );
    wp_redirect( $initiator_url );
    exit;
}
jrchamp commented 6 years ago

Normally when I see HTTP, that means that the user is providing the information (and is therefore in control of that information and can therefore modify the information) which makes me uneasy. If instead your system is setting those values and they are controlled by the server, it should work.

As a small tweak, to avoid a PHP Notice, it would be cleaner to use:

if ( empty( $_SERVER['HTTP_EMPID'] ) ) {

Alternatively, since you do not appear to be using the employee ID, it may make more sense to check for the affiliation attribute that you are using immediately after (when compared with the seemingly unused employee ID).

Given that the HTTP prefix is showing up on both of those attributes, it's possible that the Shib-Session-ID on your system is hiding in HTTP_Shib-Session-ID or HTTP_Shib_Session_ID or something similar.

michaelryanmcneill commented 6 years ago

Thanks for the help with this @jrchamp!

@jbarlow1, I'd highly recommend looking for Shib-Session-ID, however it is formatted in your environment, because shibd will attempt to sanitize that data before it is passed to your application. I'd also highly advise setting a spoof key and checking it, just to make sure that your requests are coming from shibd instead of a malicious user.

jbarlow1 commented 6 years ago

Thanks @jrchamp and @michaelryanmcneill for the help. I was able to find that we use HTTP_SHIB_SESSION_ID as the Shib-Session-ID. I altered my code from above to use this instead of the employee ID.