shane-tomlinson / browserid-wordpress

Wordpress plugin that adds Persona authentication
23 stars 16 forks source link

v 0.43 Redirect loop when working with multiple domains #18

Open MeesterPaul opened 11 years ago

MeesterPaul commented 11 years ago

In our WordPress setup we carry out all admin tasks on a different subdomain to the main site. I.e. WordPress admin pages are served from admin.examplenameofsite.com whereas the frontend is viewed through www.examplenameofsite.com (this allows all admin work to be served from a single server with the front end load balanced across multiple servers).

With v 0.43 we were experiencing a redirect loop whereby trying to view the front end pages after logging in redirected the user back to the admin dashboard, making the site unusable for logged in users. I.e. this happened:

User logs in to admin.examplenameofsite.com/wp-admin User tries to visit www.examplenameofsite.com/ User is redirected to admin.examplenameofsite.com/wp-admin

This is caused by the assertion check running on every page, and redirecting the user back to the dashboard (this may also have been the cause of other performance problems). I fixed it by checking if the user was already logged in, and skipping the assertion check if so:

--- browserid.php       (origina in v 0.43l)
+++ browserid.php       (my working copy)
@@ -164,11 +164,14 @@
                        // I18n
                        load_plugin_textdomain(c_bid_text_domain, false, dirname(plugin_basename(__FILE__)));

-                       // Check for assertion
+                       // If not already logged in, Check for assertion
+
+                       if(!is_user_logged_in()){
                        $assertion = self::Get_assertion();
                        if (!empty($assertion)) {
                                self::Check_assertion($assertion);
                        }
+                       }

                        // Enqueue BrowserID scripts
                        wp_register_script('browserid', 'https://login.persona.org/include.js', array(), '', true);

I guess the downside is that the user will not be auto-logged out if they log out of Persona, but for us that's a minor issue and I'd rather not have the overhead of checking on every page load anyway

MeesterPaul commented 11 years ago

Turned out that that fix only worked intermittently. In the end the only way I could get this to work correctly was by excluding the scripts from being loaded on anything other than the admin and login pages - loading them on the frontend pages caused the user to be logged out (although not every time). Side effects of this are

1) the logout button in the admin bar only works when you are viewing an admin page and 2) Cannot use for comments.

Annoying, but better than having to remove the system completely! For info, v 0.41 worked fine for us.

shane-tomlinson commented 11 years ago

Thanks for the detailed report @MeesterPaul, this is a situation I did not expect. This upcoming week, when I have a bit more free time, would you mind working through how your site layout works and what the desired behavior is?

When a user signs in at "admin." do they share a cookie with "www."?

Would more granular controls help here? For example:

MeesterPaul commented 11 years ago

Hi there,

Here is the login flow:

  1. The user logins in at admin.blablabla.com/wp-login.php. If the login is successful then the WordPress cookies are set on the .blablabla.com domain, so can be shared between all subdomains. The Persona cookie set by the plugin is also correctly set on the .blablabla.com domain.
  2. Once logged in, the user views all wp-admin pages on the admin.blablabla.com domain (this is enforced by some Apache rewrite rules). When viewing these pages all resources (css, scripts, etc.) are also loaded through the admin.blablabla.com domain to avoid any cross-domain problems with the scripts.
  3. When the logged in user views any non admin page (e.g. the homepage, an individual post, etc.) it is viewed through the www.blablabla.com domain. This is important as it ensures that if they cut and paste any URLs they get the www version rather than the admin version (most of our users are not at all tech-savvy).

This works very well with the standard WordPress login system which relies on the cookie as this can be set at the domain rather than subdomain level, and hence shared between the two different subdomains.

Not sure what is causing the problem with the Persona script in v. 0.43 - the issue appears to lie in the javascript rather than with the cookie it places. Not including the scripts on the non-admin pages works as a fix (hence no problems with the earlier v. 0.41 version of the script which did not place the scripts on non-admin pages) but I'm not 100% sure why I'm afraid but I'm guessing that the javascript sees the change in domain, detects it as a security risk and hence logs you out. Also, when I checked it looked like it was probably the main Persona script that was doing this rather than the login.js script bundled with the plugin. If so this is likely to be a wider a problem as a number of login systems work in a similar fashion (i.e. central log in, then redirect the user to a subdomain for further work - MailChimp springs to mind as a big example).

As a shorter term fix I'd suggest that some way of controlling on which pages the script is loaded would work. The choices would only need to be:

There would also need to be a slight reworking of the logout script run by the button on the toolbar if you only enable on admin and login pages as the script is not always available.

Hope that helps!

Paul