Commits

Andriy Kornatskyy committed 05644b8

Introduced secure decorator (to handle https permanent redirects).

  • Participants
  • Parent commits c6d24cc

Comments (0)

Files changed (5)

 .. automodule:: wheezy.http.application
    :members:
 
+wheezy.http.authorization
+-------------------------
+
+.. automodule:: wheezy.http.authorization
+   :members:
+
 wheezy.http.cache
 ---------------------
 

doc/userguide.rst

 Respond with HTTP status code 405 (Method Not Allowed) in case incoming HTTP
 request method does not match decorator constraint.
 
+@secure
+~~~~~~~
+
+Decorator :py:class:`~wheezy.http.authorization.secure` accepts only secure
+requests (those that are communication via SSL)::
+
+    @secure
+    def my_view(request):
+        ...
+
+The behavior can be controlled via ``enabled`` (in case it is
+``False`` no checks performed, defaults to ``True``).
+
+
 HTTP Request
 ------------
 :py:class:`~wheezy.http.request.HTTPRequest` is a wrapper around WSGI environ

src/wheezy/http/__init__.py

 """
 
 from wheezy.http.application import WSGIApplication
+from wheezy.http.authorization import secure
 from wheezy.http.cache import response_cache
 from wheezy.http.cachepolicy import HTTPCachePolicy
 from wheezy.http.cacheprofile import CacheProfile

src/wheezy/http/authorization.py

+
+"""
+"""
+
+from wheezy.core.url import UrlParts
+from wheezy.http.response import permanent_redirect
+
+
+def secure(wrapped=None, enabled=True):
+    """ Checks if user is accessing protected resource via SSL and if
+        not, issue permanent redirect to HTTPS location.
+
+        ``enabled`` - whenever to do any checks (defaults to ``True``).
+
+        Example::
+
+                @secure
+                def my_view(request):
+                    ...
+                    return response
+
+        Using ``enabled``::
+
+                @secure(enabled=False)
+                def my_view(request):
+                    ...
+                    return response
+    """
+    def decorate(method):
+        if not enabled:
+            return method
+
+        def check(request, *args, **kwargs):
+            if not request.secure:
+                parts = request.urlparts
+                parts = UrlParts(('https',  # scheme
+                                  parts[1],  # netloc
+                                  parts[2],  # path
+                                  parts[3],  # query
+                                  None,  # fragment
+                                  ))
+                return permanent_redirect(parts.geturl())
+            return method(request, *args, **kwargs)
+        return check
+    if wrapped is None:
+        return decorate
+    else:
+        return decorate(wrapped)

src/wheezy/http/tests/test_authorization.py

+
+"""
+"""
+
+import unittest
+
+from mock import Mock
+
+
+class SecureTestCase(unittest.TestCase):
+    """ Test the ``secure``.
+    """
+
+    def test_check_not_secure(self):
+        """ Check if request is not secure.
+
+            @secure
+            def my_view(request):
+                ...
+        """
+        from wheezy.http.authorization import secure
+        mock_request = Mock()
+        mock_request.secure = False
+        mock_request.urlparts = ('http', 'localhost:8080',
+                                 '/en/signin', None, None)
+        mock_method = Mock()
+        handler = secure()(mock_method)
+        response = handler(mock_request)
+        assert 301 == response.status_code
+        location = dict(response.headers)['Location']
+        assert 'https://localhost:8080/en/signin' == location
+
+    def test_check_secure(self):
+        """ Check if request is secure.
+        """
+        from wheezy.http.authorization import secure
+        mock_request = Mock()
+        mock_request.secure = True
+        mock_method = Mock(return_value='response')
+        handler = secure()(mock_method)
+        assert 'response' == handler(mock_request)
+
+    def test_check_not_enabled(self):
+        """ Check if request is secure.
+        """
+        from wheezy.http.authorization import secure
+        mock_request = Mock()
+        mock_method = Mock(return_value='response')
+        handler = secure(enabled=False)(mock_method)
+        assert 'response' == handler(mock_request)
+
+    def test_wrapped(self):
+        """ Check decorators
+        """
+        from wheezy.http.authorization import secure
+        mock_request = Mock()
+        mock_request.secure = True
+
+        @secure
+        def my_view(self):
+            return 'response'
+        assert 'response' == my_view(mock_request)