Redirect through HSTS granting / revoking endpoint on base domain

Since grants / revokes only happen on the base domain for simplicity,
we need to redirect through an endpoint on the base domain whenever
we perform an action that might change a user's HSTS eligibility.
This commit is contained in:
Jordan Milne
2014-07-16 01:20:58 -03:00
committed by Neil Williams
parent b70556a3ab
commit 7a4fa77a23
5 changed files with 58 additions and 9 deletions

View File

@@ -322,6 +322,8 @@ def make_map():
mc('/resetpassword', controller='forms',
action='resetpassword')
mc('/modify_hsts_grant', controller='front', action='modify_hsts_grant')
mc('/post/:action/:url_user', controller='post',
requirements=dict(action="login|reg"))
mc('/post/:action', controller='post',

View File

@@ -22,6 +22,7 @@
from r2.controllers.reddit_base import (
cross_domain,
hsts_modify_redirect,
MinimalController,
pagecache_policy,
PAGECACHE_POLICY,
@@ -521,6 +522,13 @@ class ApiController(RedditController):
if request.params.get("hoist") != "cookie":
responder._send_data(modhash = user.modhash())
responder._send_data(cookie = user.make_cookie())
if user.pref_force_https:
# The client may decide to redirect somewhere after a successful
# login, send it our HSTS grant endpoint so it can redirect through
# there and pick up the user's grant.
hsts_redir = "https://" + g.domain + "/modify_hsts_grant?dest="
responder._send_data(hsts_redir=hsts_redir)
responder._send_data(need_https=user.pref_force_https)
@validatedForm(VLoggedOut(),
user = VThrottledLogin(['user', 'passwd']),
@@ -1213,8 +1221,11 @@ class ApiController(RedditController):
form.has_errors("passwd", errors.WRONG_PASSWORD) or
form.has_errors("delete_message", errors.TOO_LONG) or
form.has_errors("confirm", errors.CONFIRM)):
redirect_url = "/?deleted=true"
if c.user.pref_force_https:
redirect_url = hsts_modify_redirect(redirect_url)
c.user.delete(delete_message)
form.redirect("/?deleted=true")
form.redirect(redirect_url)
@require_oauth2_scope("edit")
@noresponse(VUser(),

View File

@@ -23,11 +23,14 @@
from pylons.i18n import _, ungettext
from r2.controllers.reddit_base import (
base_listing,
disable_subreddit_css,
hsts_modify_redirect,
hsts_eligible,
pagecache_policy,
PAGECACHE_POLICY,
paginated_listing,
disable_subreddit_css,
RedditController,
require_https,
)
from r2 import config
from r2.models import *
@@ -54,7 +57,7 @@ from r2.lib.validator import *
from r2.lib import jsontemplates
from r2.lib import sup
import r2.lib.db.thing as thing
from r2.lib.errors import errors
from r2.lib.errors import errors, ForbiddenError
from listingcontroller import ListingController
from oauth2 import require_oauth2_scope
from api_docs import api_doc, api_section
@@ -1256,6 +1259,19 @@ class FrontController(RedditController):
page_classes=["gold-page", "gilding"],
).render()
@validate(dest=VDestination(default='/'))
def _modify_hsts_grant(self, dest):
"""Endpoint subdomains can redirect through to update HSTS grants."""
require_https()
if request.host != g.domain:
abort(ForbiddenError(errors.WRONG_DOMAIN))
self.redirect(dest, code=307)
POST_modify_hsts_grant = _modify_hsts_grant
GET_modify_hsts_grant = _modify_hsts_grant
DELETE_modify_hsts_grant = _modify_hsts_grant
PUT_modify_hsts_grant = _modify_hsts_grant
class FormsController(RedditController):
@@ -1397,6 +1413,8 @@ class FormsController(RedditController):
dest=VDestination())
def POST_logout(self, dest):
"""wipe login cookie and redirect to referer."""
if hsts_eligible():
dest = hsts_modify_redirect(dest)
self.logout()
return self.redirect(dest)

View File

@@ -22,8 +22,8 @@
from r2.lib.pages import *
from reddit_base import (
change_user_cookie_security,
delete_force_https_cookie,
set_force_https_cookie,
hsts_modify_redirect,
hsts_eligible,
)
from api import ApiController
from r2.lib.errors import BadRequestError, errors
@@ -70,7 +70,10 @@ class PostController(ApiController):
u.update_query(done = 'true')
if c.cname:
u.put_in_frame()
return self.redirect(u.unparse())
redirect_url = u.unparse()
if new_https_pref:
redirect_url = hsts_modify_redirect(u)
return self.redirect(redirect_url)
def GET_over18(self):
return BoringPage(_("over 18?"),
@@ -122,6 +125,8 @@ class PostController(ApiController):
return LoginPage(user_login = request.POST.get('user'),
dest = dest).render()
if hsts_eligible():
dest = hsts_modify_redirect(dest)
return self.redirect(dest)
@validate(dest = VDestination(default = "/"))
@@ -134,6 +139,8 @@ class PostController(ApiController):
return LoginPage(user_reg = request.POST.get('user'),
dest = dest).render()
if hsts_eligible():
dest = hsts_modify_redirect(dest)
return self.redirect(dest)
def GET_login(self, *a, **kw):

View File

@@ -124,8 +124,12 @@ r.login.ui = {
}
}
this.popup.showLogin(true, dest && $.proxy(function() {
this.popup.showLogin(true, dest && $.proxy(function(result) {
this.popup.loginForm.$el.addClass('working')
var hsts_redir = result.json.data.hsts_redir
if(hsts_redir) {
dest = hsts_redir + encodeURIComponent(dest)
}
window.location = dest
}, this))
@@ -176,8 +180,15 @@ r.ui.LoginForm.prototype = $.extend(new r.ui.Form(), {
this.$el.addClass('working')
var base = r.config.extension ? '/.'+r.config.extension : '/',
defaultDest = /\/login\/?$/.test($.url().attr('path')) ? base : window.location,
destParam = this.$el.find('input[name="dest"]').val()
window.location = destParam || defaultDest
destParam = this.$el.find('input[name="dest"]').val(),
hsts_redir = result.json.data.hsts_redir
var redir = destParam || defaultDest
// We might need to redirect through the base domain to grab
// our HSTS grant.
if (hsts_redir) {
redir = hsts_redir + encodeURIComponent(redir)
}
window.location = redir
}
} else {
r.ui.Form.prototype._handleResult.call(this, result)