Skip to content

Commit

Permalink
Merge pull request #13 from karthikbangera87/master
Browse files Browse the repository at this point in the history
# Issue 12 resolution.  Thanks Karthik!
  • Loading branch information
tgs committed Jul 2, 2014
2 parents 4874f1b + 628b7fc commit 75bfd37
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 10 deletions.
3 changes: 3 additions & 0 deletions badgekit_webhooks/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ class BadgekitWebhooksAppConf(AppConf):
PROGRAM = None
"The 'program' slug to use with the Badgekit API"

VERIFY_ASSERTION_URLS = True
"Whether or not to verify that an assertion comes from BADGEKIT_API_URL."

class Meta:
prefix = 'badgekit'

Expand Down
26 changes: 21 additions & 5 deletions badgekit_webhooks/tests/claim_tests.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import unicode_literals
from django.test import TestCase
from django.core.urlresolvers import reverse
from django.conf import settings
import json
import jwt
import hashlib
Expand All @@ -10,6 +11,8 @@

from badgekit_webhooks import views

settings.BADGEKIT_API_URL = "http://example.com"

badge_info_dummy = {
'badge': 'http://example.com/badge',
'issuer': 'http://example.com/issuer',
Expand All @@ -19,13 +22,14 @@

def register_dummy():
httpretty.register_uri(httpretty.GET,
re.compile(r'evil.com/.*'),
re.compile(r'example.com/.*'),
body=json.dumps(badge_info_dummy))
httpretty.register_uri(httpretty.GET,
re.compile(r'example.com/.*'),
re.compile(r'wrongissuer.com/.*'),
body=json.dumps(badge_info_dummy))



class ClaimPageTest(TestCase):
@httpretty.activate
def testCanGetClaimPage(self):
Expand All @@ -37,21 +41,33 @@ def testCanGetClaimPage(self):
@httpretty.activate
def testQuotesDoNotAppear(self):
register_dummy()
url = views.create_claim_url(b'http://evil.com/quote"quote')
url = views.create_claim_url(b'http://example.com/quote"quote')
resp = self.client.get(url)
self.assertFalse(b'quote"quote' in resp.content)

@httpretty.activate
def testBracketsDoNotAppear(self):
register_dummy()
url = views.create_claim_url(b"http://evil.com/angle<angle>angle")
url = views.create_claim_url(b"http://example.com/angle<angle>angle")
resp = self.client.get(url)
self.assertFalse(b"angle<" in resp.content)
self.assertFalse(b"angle>" in resp.content)

@httpretty.activate
def testMoreChars(self):
register_dummy()
url = views.create_claim_url(b"http://evil.com/semi;dquote\"")
url = views.create_claim_url(b"http://example.com/semi;dquote\"")
resp = self.client.get(url)
self.assertFalse(b'dquote"' in resp.content)


class AssertionVerifyTests(TestCase):
# Test that it rejects evil.com
@httpretty.activate
def cantGetWrongClaimURL(self):
with self.settings(BADGEKIT_API_URL="http://example.com/",
BADGEKIT_VERIFY_ASSERTION_URL=True):
resp = self.client.get(views.create_claim_url(b"http://evil.com/angle"))
self.assertEqual(resp.status_code, 400)
# We tested that it accepts example.com above with testCanGetClaimPage

22 changes: 19 additions & 3 deletions badgekit_webhooks/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import requests
import logging
from django.conf import settings
from urlparse import urlparse
from django.http import HttpResponseBadRequest
import json


Expand Down Expand Up @@ -30,16 +32,19 @@ def urlsafe_base64_decode(s):
decode_param = urlsafe_base64_decode
encode_param = urlsafe_base64_encode


def get_image_for_assertion(assertion_url):
"""
Given a badge assertion URL, return an image for that assertion.
If the assertion is not available or parseable, returns a default
image, which is settings.BADGEKIT_DEFAULT_BADGE_IMAGE.
"""
# TODO: make sure various URLs are subjected to a whitelist test.
# Maybe also check that they are reasonable size, etc?
# Make sure assertion is one of the badges under the purview of this system
if (test_whitelist_assertion_url(assertion_url)):
pass
else:
return settings.BADGEKIT_DEFAULT_BADGE_IMAGE

try:
assertion_resp = requests.get(assertion_url)
assertion_obj = json.loads(assertion_resp.text)
Expand Down Expand Up @@ -73,6 +78,17 @@ def get_image_for_assertion(assertion_url):
# logging.exception('Problem while determining image for assertion %s' % assertion_url)
# return settings.BADGEKIT_DEFAULT_BADGE_IMAGE

def test_whitelist_assertion_url(assertion_url):
# For now, the only whitelisted site is the badgekit install
whitelisturl = settings.BADGEKIT_API_URL
parseofwhitelisturl = urlparse(whitelisturl)

parseofassertionurl = urlparse(assertion_url)

if((parseofassertionurl.scheme == parseofwhitelisturl.scheme) and (parseofassertionurl.netloc == parseofwhitelisturl.netloc)):
return True
else:
return False



Expand Down
7 changes: 5 additions & 2 deletions badgekit_webhooks/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import jwt
import hashlib
import logging
from urlparse import urlparse
from django.core.urlresolvers import reverse
from . import utils
from django.contrib.admin.views.decorators import staff_member_required
Expand Down Expand Up @@ -119,8 +120,10 @@ def create_claim_url(assertionUrl):
def claim_page(request, b64_assertion_url):
# The URL should be ASCII encoded: only IRIs use higher Unicode chars. Right????
assertionUrl = utils.decode_param(b64_assertion_url).decode('ascii')

# TODO validate the URL against a whitelist
if(utils.test_whitelist_assertion_url(assertionUrl)):
pass
else:
return HttpResponseBadRequest("This site only allows you to claim badges issued here. It seems the link you clicked doesn't meet this condition. Please contact us if you think this was in error.")

api = models.get_badgekit_api()
assertion = api.get_public_url(assertionUrl)
Expand Down
1 change: 1 addition & 0 deletions runtests.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
SITE_ID=1,
ROOT_URLCONF="badgekit_webhooks.tests.urls",
SECRET_KEY="notasecret",
BADGEKIT_VERIFY_ASSERTION_URLS = False,
)


Expand Down

0 comments on commit 75bfd37

Please sign in to comment.