Skip to content

Commit

Permalink
Merge pull request #269 from goodtune/disallowedhost
Browse files Browse the repository at this point in the history
Added middleware that raises DisallowedHost instead of 404
  • Loading branch information
bernardopires committed Aug 1, 2015
2 parents 6a3a3d7 + 3068254 commit 0b15c16
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 5 deletions.
5 changes: 4 additions & 1 deletion docs/install.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,16 @@ Add `tenant_schemas.routers.TenantSyncRouter` to your `DATABASE_ROUTERS` setting
DATABASE_ROUTERS = (
'tenant_schemas.routers.TenantSyncRouter',
)
Add the middleware ``tenant_schemas.middleware.TenantMiddleware`` to the top of ``MIDDLEWARE_CLASSES``, so that each request can be set to use the correct schema.

If the hostname in the request does not match a valid tenant ``domain_url``, a HTTP 404 Not Found will be returned. If you'd like to raise ``DisallowedHost`` and a HTTP 400 response instead, use the ``tenant_schemas.middleware.SuspiciousTenantMiddleware``.

.. code-block:: python
MIDDLEWARE_CLASSES = (
'tenant_schemas.middleware.TenantMiddleware',
# 'tenant_schemas.middleware.SuspiciousTenantMiddleware',
#...
)
Expand Down
28 changes: 24 additions & 4 deletions tenant_schemas/middleware.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import DisallowedHost
from django.db import connection
from django.shortcuts import get_object_or_404
from django.http import Http404
from tenant_schemas.utils import (get_tenant_model, remove_www,
get_public_schema_name)

Expand All @@ -12,6 +13,8 @@ class TenantMiddleware(object):
Selects the proper database schema using the request host. Can fail in
various ways which is better than corrupting or revealing data.
"""
TENANT_NOT_FOUND_EXCEPTION = Http404

def hostname_from_request(self, request):
""" Extracts hostname from request. Used for custom requests filtering.
By default removes the request's port and common prefixes.
Expand All @@ -24,9 +27,13 @@ def process_request(self, request):
connection.set_schema_to_public()
hostname = self.hostname_from_request(request)

request.tenant = get_object_or_404(
get_tenant_model(), domain_url=hostname)
connection.set_tenant(request.tenant)
TenantModel = get_tenant_model()
try:
request.tenant = TenantModel.objects.get(domain_url=hostname)
connection.set_tenant(request.tenant)
except TenantModel.DoesNotExist:
raise self.TENANT_NOT_FOUND_EXCEPTION(
'No tenant for hostname "%s"' % hostname)

# Content type can no longer be cached as public and tenant schemas
# have different models. If someone wants to change this, the cache
Expand All @@ -40,3 +47,16 @@ def process_request(self, request):
# Do we have a public-specific urlconf?
if hasattr(settings, 'PUBLIC_SCHEMA_URLCONF') and request.tenant.schema_name == get_public_schema_name():
request.urlconf = settings.PUBLIC_SCHEMA_URLCONF


class SuspiciousTenantMiddleware(TenantMiddleware):
"""
Extend the TenantMiddleware in scenario where you need to configure
``ALLOWED_HOSTS`` to allow ANY domain_url to be used because your tenants
can bring any custom domain with them, as opposed to all tenants being a
subdomain of a common base.
See https://github.com/bernardopires/django-tenant-schemas/pull/269 for
discussion on this middleware.
"""
TENANT_NOT_FOUND_EXCEPTION = DisallowedHost

0 comments on commit 0b15c16

Please sign in to comment.