subdomains: Enforce subdomain checks on every API endpoint.

This ensures that everything is using the correct subdomain for
requests.  While it probably wouldn't be a real security problem for
the wrong subdomain to work, this enforcement is essential to catching
bugs in the product and users' API scripts.
This commit is contained in:
Tim Abbott
2016-08-13 19:16:39 -07:00
committed by Tim Abbott
parent a4e5450ace
commit b5b00e3a36

View File

@@ -189,6 +189,15 @@ def validate_api_key(request, role, api_key, is_webhook=False):
except AttributeError:
# Deployment objects don't have realms
pass
if (not check_subdomain(get_subdomain(request), profile.realm.subdomain)
# Allow access to localhost for Tornado
and not (settings.RUNNING_INSIDE_TORNADO and
request.META["SERVER_NAME"] == "127.0.0.1" and
request.META["REMOTE_ADDR"] == "127.0.0.1")):
logging.warning("User %s attempted to access API on wrong subdomain %s" % (
profile.email, get_subdomain(request)))
raise JsonableError(_("Account is not associated with this subdomain"))
return profile
# Use this for webhook views that don't get an email passed in.
@@ -212,6 +221,10 @@ def api_key_only_webhook_view(client_name):
raise JsonableError(_("Account not active"))
if user_profile.realm.deactivated:
raise JsonableError(_("Realm for account has been deactivated"))
if not check_subdomain(get_subdomain(request), user_profile.realm.subdomain):
logging.warning("User %s attempted to access webhook API on wrong subdomain %s" % (
user_profile.email, get_subdomain(request)))
raise JsonableError(_("Account is not associated with this subdomain"))
request.user = user_profile
request._email = user_profile.email
@@ -422,6 +435,15 @@ def authenticate_log_and_execute_json(request, view_func, *args, **kwargs):
raise JsonableError(_("Realm for account has been deactivated"))
if user_profile.is_incoming_webhook:
raise JsonableError(_("Webhook bots can only access webhooks"))
if (not check_subdomain(get_subdomain(request), user_profile.realm.subdomain) and
# Exclude the SOCKET requests from this filter; they were
# checked when the original websocket request reached Tornado
not (request.method == "SOCKET" and
request.META['SERVER_NAME'] == "127.0.0.1")):
logging.warning("User %s attempted to access JSON API on wrong subdomain %s" % (
user_profile.email, get_subdomain(request)))
raise JsonableError(_("Account is not associated with this subdomain"))
process_client(request, user_profile, True)
request._email = user_profile.email
return view_func(request, user_profile, *args, **kwargs)