WordPress.org

Make WordPress Core

Opened 7 years ago

Closed 7 years ago

Last modified 7 years ago

#29156 closed defect (bug) (fixed)

$rp_path does not respect SITECOOKIEPATH/COOKIEPATH

Reported by: WALoeIII Owned by: nacin
Milestone: 4.0 Priority: high
Severity: major Version: 4.0
Component: Login and Registration Keywords: has-patch needs-testing
Focuses: administration Cc:

Description

In wp-login.php

The wp-resetpass- cookie is set if a user hits with a key. This value is then transitioned to a cookie written with a path.

list( $rp_path ) = explode( '?', wp_unslash( $_SERVER['REQUEST_URI'] ) );
setcookie( $rp_cookie, $value, 0, $rp_path, COOKIE_DOMAIN, is_ssl(), true );


In my installation with siteurl and home set to www.mydomain.com/blog this results in a cookie with a path of /wp-login.php instead of /blog/wp-login.php, as a result the user can never reset their password.

Attachments (2)

rp_path.patch (495 bytes) - added by WALoeIII 7 years ago.
Simple patch, may not cover all cases.
29156.diff (1.3 KB) - added by mdawaffe 7 years ago.

Download all attachments as: .zip

Change History (27)

@WALoeIII
7 years ago

Simple patch, may not cover all cases.

#1 @johnbillion
7 years ago

  • Focuses administration added
  • Milestone changed from Awaiting Review to Future Release

This code was introduced in 3.9.2 (r29327) and backported to 3.8.4 and 3.7.4. I'll run some tests to confirm the bug shortly.

#2 @johnbillion
7 years ago

  • Version changed from trunk to 3.9.2

#3 @SergeyBiryukov
7 years ago

  • Milestone changed from Future Release to 4.0
  • Version changed from 3.9.2 to trunk

This was technically introduced in trunk and backported to 3.9.2, 3.8.4, and 3.7.4.

Moving to 4.0 to get more eyes on this.

#4 @gregsullivan
7 years ago

I'm also experiencing this on a Multisite install with WordPress in a subdirectory. The cookie's path is set to /wp-login.php, and the form submits to /subdirectory/wp-login.php as described, making the cookie inaccessible.

I'm handling password resets manually for the time being.

#5 @nacin
7 years ago

I don't understand this one, unfortunately.

If wp-login.php is at /blog/wp-login.php, then that would be the value of $_SERVER['REQUEST_URI'], and it would be the path that would get set.

Can you describe the actual steps? You start on X URL, it posts to Y URL, the email contains Z URL, which takes you to W URL, etc... What's the actual configuration of your network as a subdirectory install, rewrite rules, and such?

#6 @nacin
7 years ago

  • Keywords reporter-feedback added

#7 @gregsullivan
7 years ago

For me, it's as follows:

  1. Request lost password link at http://domain.com/wp-login.php?action=lostpassword
  2. Receive email; contains link to http://domain.com/wp-login.php?action=rp&key=<key>&login=<username>
  3. Click link; 301 redirect to http://domain.com/wp-login.php?action=rp

At this point the cookie is set, but the form on that page has as its action:

http://domain.com/subdirectory/wp-login.php?action=resetpass

Submitting the form results in, "Sorry, that key does not appear to be valid."

#8 @nacin
7 years ago

Can you check the value of $_SERVER['REQUEST_URI'] when visiting http://domain.com/wp-login.php? If it's anything other than /wp-login.php then this is a server configuration issue (or possibly a bug in wp_fix_server_vars(), but unlikely).

#9 @gregsullivan
7 years ago

At login_head, $_SERVER['REQUEST_URI'] has a value of /wp-login.php when going directly to the login form.

As of step three in the steps above, the value is /wp-login.php?action=rp

The only rewrite rule that looks relevant is this one:

RewriteRule ^([_0-9a-zA-Z-]+/)?(.*\.php)$ subdirectory/$2 [L]

(As supplied by My Sites > Settings > Network Setup.)

Last edited 7 years ago by gregsullivan (previous) (diff)

#10 @nacin
7 years ago

Okay, I misread, but I don't fully understand your setup. Could you give me a better idea of what's going on here? Do you have sites at domain.com, domain.com/subdirectory, domain.com/blog, etc.? Which is the main site on the network?

#11 @gregsullivan
7 years ago

I followed these instructions for installation:

http://codex.wordpress.org/Giving_WordPress_Its_Own_Directory

Then followed the usual instructions for creating a network.

The network uses subdirectories. So domain.com is the main site, WordPress is installed at domain.com/subdirectory, and sites exist at domain.com/site2, domain.com/site3, etc.

#12 @gregsullivan
7 years ago

Is it possible that this line in wp-login.php:

<form name="lostpasswordform" id="lostpasswordform" action="<?php echo esc_url( site_url( 'wp-login.php?action=lostpassword', 'login_post' ) ); ?>" method="post">

is causing the problem? Could home_url be used instead of site_url?

Alternatively, would it make sense to take site_url into account when setting the cookie?

Last edited 7 years ago by gregsullivan (previous) (diff)

#13 @zbtirrell
7 years ago

I attempted to reproduce this issue on a fresh subdirectory network install of 4.0 and did not get the same behavior when following the same steps.

#14 @nacin
7 years ago

Roughly, home_url() is wherever the homepage is located, while site_url() is wherever the site's files are located.

If you had example.com with WordPress at example.com/wordpress, then home_url() would return the former and site_url() would return the latter. site_url() is thus used whenever we're targeting a particular file, whether that's wp-login.php or in something like includes_url() for example.com/wordpress/wp-includes.

I'd be curious to know what the home and siteurl option values are for the various sites. For a post-3.5 multisite setup that puts WP into a subdirectory, it should look like this:

  • main site: home url is domain.com, siteurl is domain.com/wordpress
  • additional sites: home url and siteurl are both domain.com/sitename (since we require rewrite rules for multisite, we can dynamically rewrite things and don't require home url and siteurl to be different)

siteurl *is* taken to account when setting the cookie because wp-login.php would be located at site_url( 'wp-login.php' ). Using REQUEST_URI was a matter of not wreaking havoc when someone was doing crazy/weird filtering of URLs or whatever.

#15 follow-up: @nacin
7 years ago

  • Keywords reporter-feedback removed
  • Priority changed from normal to high
  • Severity changed from normal to major

Okay, I could see how this could go wrong.

You're going to http://domain.com/wp-login.php. This is the network site url, but not the site url for the main site. That'd be http://domain.com/wordpress/wp-login.php. http://domain.com/wp-login.php isn't actually the site url for any site in this setup.

When you submit, you're actually submitting to http://domain.com/wordpress/wp-login.php, since the form actions are site_url() throughout this process. The email uses network_site_url() though, which links you back to http://domain.com/wp-login.php. At that point, you then get redirected (after the key and username is stripped from the URL) to http://domain.com/wp-login.php again. But the form action submits to site_url(), which is http://domain.com/wordpress/wp-login.php.

Two possible solutions:

  • Always post to network_site_url().
  • Link to site_url() in the email.

I like the first one, since for whatever reason we already seem to want it to go through the central location.

#16 @nacin
7 years ago

To work around this (and to confirm it's a problem), when visiting a password reset link, change its path to http://domain.com/wordpress/wp-login.php. Or, change siteurl for the main site to http://domain.com (could have other side effects but rewrite rules should cover it).

#17 @gregsullivan
7 years ago

I attempted to reproduce this issue on a fresh subdirectory network install of 4.0 and did not get the same behavior when following the same steps.

I went through the subdirectory installation instructions on a clean install and confirmed that the bug is not present outside of Multisite; then, I converted to a network, and the bug is present in 3.9.2.

I then upgraded to the latest nightly, and the bug is present there as well.

To work around this (and to confirm it's a problem), when visiting a password reset link, change its path to http://domain.com/wordpress/wp-login.php.

This works. If you have any interest in trying it, I can create an account for you on my test installation.

Or, change siteurl for the main site to http://domain.com (could have other side effects but rewrite rules should cover it).

This also works; I didn't check for further side effects, but the password change was successful.

#18 in reply to: ↑ 15 ; follow-up: @mdawaffe
7 years ago

Replying to nacin:

  • Always post to network_site_url().

For all forms on wp-login.php or just the reset one? This seems better to me too, but I wonder if it's more likely to break something else.

#19 in reply to: ↑ 18 @nacin
7 years ago

Replying to mdawaffe:

Replying to nacin:

  • Always post to network_site_url().

For all forms on wp-login.php or just the reset one? This seems better to me too, but I wonder if it's more likely to break something else.

Just for reset, which is already attempting to only go through the main site, so we're only trying to further handle this as it was intended. For everything else, we'd probably break things. The most obvious example is logging in to a particular site and getting redirected to that site's dashboard.)

@mdawaffe
7 years ago

#20 @mdawaffe
7 years ago

  • Keywords has-patch needs-testing added

attachment:29156.diff

Use network_site_url() for the lostpasswordform (I don't think this is strictly necessary) and the resetpassform (this is necessary).

#21 @nacin
7 years ago

  • Owner set to nacin
  • Resolution set to fixed
  • Status changed from new to closed

In 29631:

Password resets: Use network_site_url() for form actions.

props mdawaffe.
fixes #29156.

#22 @nacin
7 years ago

In 29638:

Password resets: Use network_site_url() for form actions.

Merges [29631] to the 3.9 branch.

props mdawaffe.
fixes #29156.

#23 @nacin
7 years ago

In 29639:

Password resets: Use network_site_url() for form actions.

Merges [29631] to the 3.8 branch.

props mdawaffe.
fixes #29156.

#24 @nacin
7 years ago

In 29640:

Password resets: Use network_site_url() for form actions.

Merges [29631] to the 3.7 branch.

props mdawaffe.
fixes #29156.

#25 @nacin
7 years ago

For anyone watching, I'm not planning on 3.7.5 / 3.8.5 / 3.9.3. Would simply like to propagate this fix if those versions are ever released.

Note: See TracTickets for help on using tickets.