Commit 1f27676a authored by Sofia Papagiannaki's avatar Sofia Papagiannaki
Browse files

astakos oa2: Handle unicode query parameters in the redirection endpoint

parent b1126fe8
......@@ -36,10 +36,13 @@ import urlparse
import uuid
import datetime
import json
import urltools
from base64 import b64encode, b64decode
from hashlib import sha512
from synnefo.util.text import uenc
import logging
logger = logging.getLogger(__name__)
......@@ -47,8 +50,12 @@ logger = logging.getLogger(__name__)
def urlencode(params):
if hasattr(params, 'urlencode') and callable(getattr(params, 'urlencode')):
return params.urlencode()
for k in params:
params[uenc(k)] = uenc(params.pop(k))
return urllib.urlencode(params)
def normalize(url):
return urltools.normalize(uenc(url))
def handles_oa2_requests(func):
def wrapper(self, *args, **kwargs):
......@@ -450,7 +457,7 @@ class SimpleBackend(object):
scope=None, token_type="Bearer"):
if scope and code_instance.scope != scope:
raise OA2Error("Invalid scope")
if redirect_uri != code_instance.redirect_uri:
if normalize(redirect_uri) != normalize(code_instance.redirect_uri):
raise OA2Error("The redirect uri does not match "
"the one used during authorization")
token = self.add_token_for_client(token_type, code_instance)
......@@ -562,7 +569,8 @@ class SimpleBackend(object):
raise OA2Error("Redirect uri length limit exceeded")
if not client.redirect_uri_is_valid(redirect_uri):
raise OA2Error("Mismatching redirect uri")
if expected_value is not None and redirect_uri != expected_value:
if expected_value is not None and \
normalize(redirect_uri) != normalize(expected_value):
raise OA2Error("Invalid redirect uri")
else:
try:
......@@ -574,7 +582,7 @@ class SimpleBackend(object):
def validate_state(self, client, params, headers):
return params.get('state')
raise OA2Error("Invalid state")
#raise OA2Error("Invalid state")
def validate_scope(self, client, params, headers):
scope = params.get('scope')
......
......@@ -38,6 +38,7 @@ import base64
import datetime
from collections import namedtuple
from urltools import normalize
from django.test import TransactionTestCase as TestCase
from django.test import Client as TestClient
......@@ -49,6 +50,8 @@ from astakos.oa2 import settings
from astakos.oa2.models import Client, AuthorizationCode, Token
from astakos.im.tests import common
from synnefo.util.text import uenc
ParsedURL = namedtuple('ParsedURL', ['host', 'scheme', 'path', 'params',
'url'])
......@@ -216,8 +219,10 @@ class TestOA2(TestCase, URLAssertionsMixin):
self.assertEqual(token.token_type, token_type)
self.assertEqual(token.grant_type, 'authorization_code')
#self.assertEqual(token.user, expected.get('user'))
self.assertEqual(token.redirect_uri, expected.get('redirect_uri'))
self.assertEqual(token.scope, expected.get('scope'))
self.assertEqual(normalize(uenc(token.redirect_uri)),
normalize(uenc(expected.get('redirect_uri'))))
self.assertEqual(normalize(uenc(token.scope)),
normalize(uenc(expected.get('scope'))))
self.assertEqual(token.state, expected.get('state'))
except Token.DoesNotExist:
self.fail("Invalid access_token")
......@@ -271,7 +276,7 @@ class TestOA2(TestCase, URLAssertionsMixin):
# mixed up credentials/client_id's
self.client.set_credentials('client1', 'secret')
r = self.client.authorize_code('client2')
r = self.client.authorize_code('client3')
self.assertEqual(r.status_code, 400)
self.assertCount(AuthorizationCode, 0)
......@@ -342,7 +347,7 @@ class TestOA2(TestCase, URLAssertionsMixin):
# valid request: trusted client
params = {'redirect_uri': self.client3_redirect_uri,
'scope': self.client3_redirect_uri,
'extra_param': '123'}
'extra_param': 'γιουνικοντ'}
self.client.set_credentials('client3', 'secret')
r = self.client.authorize_code('client3', urlparams=params)
self.assertEqual(r.status_code, 302)
......@@ -413,6 +418,27 @@ class TestOA2(TestCase, URLAssertionsMixin):
r = self.client.authorize_code('client3', urlparams=params)
self.assertEqual(r.status_code, 400)
# redirect uri descendant
redirect_uri = '%s/more?α=γιουνικοντ' % self.client3_redirect_uri
params['redirect_uri'] = redirect_uri
self.client.set_credentials('client3', 'secret')
r = self.client.authorize_code('client3', urlparams=params)
self.assertEqual(r.status_code, 302)
self.assertCount(AuthorizationCode, 6)
# redirect is valid
redirect = self.get_redirect_url(r)
self.assertParam(redirect, "code")
self.assertParamEqual(redirect, "state", 'csrfstate')
self.assertNoParam(redirect, "extra_param")
self.assertHost(redirect, "server3.com")
self.assertPath(redirect, urlparse.urlparse(redirect_uri).path)
code = AuthorizationCode.objects.get(code=redirect.params['code'][0])
self.assertEqual(code.state, 'csrfstate')
self.assertEqual(normalize(uenc(code.redirect_uri)),
normalize(uenc(redirect_uri)))
def test_get_token(self):
# invalid method
r = self.client.get(self.client.token_url)
......@@ -526,3 +552,26 @@ class TestOA2(TestCase, URLAssertionsMixin):
'scope': redirect_uri,
'state': None}
self.assert_access_token_response(r, expected)
redirect_uri = '%s/more?α=γιουνικοντ' % self.client3_redirect_uri
params = {'redirect_uri': redirect_uri}
r = self.client.authorize_code('client3', urlparams=params)
self.assertCount(AuthorizationCode, 1)
redirect = self.get_redirect_url(r)
code_instance = AuthorizationCode.objects.get(
code=redirect.params['code'][0])
# valid request
self.client.set_credentials('client3', 'secret')
r = self.client.access_token(code_instance.code,
redirect_uri='%sa' % redirect_uri)
self.assertEqual(r.status_code, 400)
r = self.client.access_token(code_instance.code,
redirect_uri=redirect_uri)
self.assertCount(AuthorizationCode, 0) # assert code is consumed
self.assertCount(Token, 3)
expected = {'redirect_uri': redirect_uri,
'scope': redirect_uri,
'state': None}
self.assert_access_token_response(r, expected)
......@@ -74,6 +74,7 @@ INSTALL_REQUIRES = [
'django-ratelimit==0.1',
'requests',
'inflect',
'urltools',
'snf-django-lib',
'snf-branding',
'snf-webproject',
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment