Skip to content
This repository has been archived by the owner on Jan 18, 2020. It is now read-only.

Commit

Permalink
Merge 968ccc0 into 7d83f48
Browse files Browse the repository at this point in the history
  • Loading branch information
bruth committed Feb 11, 2014
2 parents 7d83f48 + 968ccc0 commit bd1b54f
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 3 deletions.
64 changes: 62 additions & 2 deletions serrano/resources/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
from urlparse import urlparse
from django.http import HttpResponse
from django.utils.http import is_safe_url
from django.conf import settings as django_settings
from django.conf.urls import patterns, url
from django.core.urlresolvers import reverse
from django.contrib.auth import authenticate, login
from restlib2.resources import Resource
from restlib2.http import codes
import serrano
from serrano.conf import dep_supported
from serrano.conf import dep_supported, settings
from serrano.tokens import token_generator
from serrano import cors
from .base import BaseResource

API_VERSION = '{major}.{minor}.{micro}'.format(**serrano.__version_info__)
Expand Down Expand Up @@ -55,6 +61,9 @@ def get(self, request):
'exporter': {
'href': uri(reverse('serrano:data:exporter')),
},
'ping': {
'href': uri(reverse('serrano:ping')),
},
}
}

Expand All @@ -79,6 +88,57 @@ def post(self, request):
return HttpResponse('Invalid credentials', status=401)


class Ping(Resource):
"""Dedicated resource for pinging the service. This is used for detecting
session timeouts. This resource does not impact the session on a request
and thus allows for the session to naturally timeout.
The response code will always be 200, however the payload will contain the
real code and status, such as 'timeout', with any other relevant
information. This decision was facilitate browser clients whose behavior
will vary when using real response codes.
"""
def process_response(self, request, response):
response = super(Ping, self).process_response(request, response)
return cors.patch_response(request, response, self.allowed_methods)

def get(self, request):
resp = {
'code': codes.ok,
'status': 'ok',
}

if settings.AUTH_REQUIRED:
user = getattr(request, 'user')

if not user or not user.is_authenticated():
ref = request.META.get('HTTP_REFERER', '')

if ref and is_safe_url(url=ref, host=request.get_host()):
# Construct redirect to referring page since redirecting
# back to an API endpoint does not useful
path = urlparse(ref).path
else:
path = django_settings.LOGIN_REDIRECT_URL

location = '{0}?next={1}'.format(django_settings.LOGIN_URL,
path)
url = request.build_absolute_uri(location)

resp = {
'code': codes.found,
'status': 'timeout',
'location': url,
}

return self.render(request, resp)


root_resource = Root()
ping_resource = Ping()

urlpatterns = patterns('', url(r'^$', root_resource, name='root'))
urlpatterns = patterns(
'',
url(r'^$', root_resource, name='root'),
url(r'^ping/$', ping_resource, name='ping'),
)
2 changes: 1 addition & 1 deletion serrano/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
serrano_patterns = patterns(
'',

url(r'^$',
url(r'^',
include('serrano.resources')),

url(r'^categories/',
Expand Down
34 changes: 34 additions & 0 deletions tests/cases/resources/tests/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ def test_get(self):
'concepts': {'href': 'http://testserver/api/concepts/'},
'preview': {'href': 'http://testserver/api/data/preview/'},
'sets': {'href': 'http://testserver/api/sets/'},
'ping': {'href': 'http://testserver/api/ping/'},
},
})

Expand Down Expand Up @@ -230,3 +231,36 @@ def test_bad_urls(self):
url = '/api/test/{0}/revisions/'.format(view.id)
response = self.client.get(url, HTTP_ACCEPT='application/json')
self.assertEqual(response.status_code, codes.not_found)


class PingResourceTestCase(AuthenticatedBaseTestCase):
@override_settings(SERRANO_AUTH_REQUIRED=True)
def test(self):
response = self.client.get('/api/ping/',
HTTP_ACCEPT='application/json')
self.assertEqual(json.loads(response.content)['status'], 'ok')

# emulate session timeout..
self.client.logout()

response = self.client.get('/api/ping/',
HTTP_ACCEPT='application/json',
HTTP_REFERER='http://testserver/query/')

data = json.loads(response.content)
self.assertEqual(data['status'], 'timeout')
self.assertEqual(data['location'],
'http://testserver/accounts/login/?next=/query/')

@override_settings(SERRANO_AUTH_REQUIRED=True, LOGIN_REDIRECT_URL='/')
def test_nonsafe_referer(self):
self.client.logout()

response = self.client.get('/api/ping/',
HTTP_ACCEPT='application/json',
HTTP_REFERER='http://example.com/spam/')

data = json.loads(response.content)
self.assertEqual(data['status'], 'timeout')
self.assertEqual(data['location'],
'http://testserver/accounts/login/?next=/')

0 comments on commit bd1b54f

Please sign in to comment.