Refactoring tests.

This commit is contained in:
Ignacio Fiorentino 2016-04-14 16:22:38 -03:00
parent 49f011b52b
commit bc6a083571
4 changed files with 69 additions and 186 deletions

View file

@ -1,15 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQC/O5N0BxpMVbht7i0bFIQyD0q2O4mutyYLoAQn8skYEbDUmcwp
9dRe7GTHiDrMqJ3gW9hTZcYm7dt5rhjFqdCYK504PDOcK8LGkCN2CiWeRbCAwaz0
Wgh3oJfbTMuYV+LWLFAAPxN4cyN6RoE9mlk7vq7YNYVpdg0VNMAKvW95dQIDAQAB
AoGBAIBMdxw0G7e1Fxxh3E87z4lKaySiAzh91f+cps0qfTIxxEKOwMQyEv5weRjJ
VDG0ut8on5UsReoeUM5tOF99E92pEnenI7+VfnFf04xCLcdT0XGbKimb+5g6y1Pm
8630TD97tVO0ASHcrXOtkSTYNdAUDcqeJUTOwgW0OD3Hyb8BAkEAxODr/Mln86wu
NhnxEVf9wuEJxX6JUjnkh62wIWYbZU61D+pIrtofi/0+AYn/9IeBCTDNIM4qTzsC
HV/u/3nmwQJBAPiooD4FYBI1VOwZ7RZqR0ZyQN0IkBsfw95K789I1lBeXh34b6r6
dik4A72guaAZEuxTz3MPjbSrflGjq47fE7UCQQCPsDSrpvcGYbjMZXyKkvSywXlX
OXXRnE0NNReiGJqQArSk6/GmI634hpg1mVlER41GfuaHNdCtSLzPYY/Vx0tBAkAc
QFxkb4voxbJuWMu9HjoW4OhJtK1ax5MjcHQqouXmn7IlyZI2ZNqD+F9Ebjxo2jBy
NVt+gSfifRGPCP927hV5AkEAwFu9HZipddp8PM8tyF1G09+s3DVSCR3DLMBwX9NX
nGA9tOLYOSgG/HKLOWD1qT0G8r/vYtFuktCKMSidVMp5sw==
-----END RSA PRIVATE KEY-----

View file

@ -42,13 +42,12 @@ def create_fake_client(response_type, is_public=False):
""" """
client = Client() client = Client()
client.name = 'Some Client' client.name = 'Some Client'
client.client_id = str(random.randint(1, 999999)).zfill(6)
if is_public: if is_public:
client.client_type = 'public' client.client_type = 'public'
client.client_id = 'p123'
client.client_secret = '' client.client_secret = ''
else: else:
client.client_id = 'c123' client.client_secret = str(random.randint(1, 999999)).zfill(6)
client.client_secret = '456'
client.response_type = response_type client.response_type = response_type
client.redirect_uris = ['http://example.com/'] client.redirect_uris = ['http://example.com/']
@ -57,17 +56,6 @@ def create_fake_client(response_type, is_public=False):
return client return client
def create_rsakey():
"""
Generate and save a sample RSA Key.
"""
fullpath = os.path.abspath(os.path.dirname(__file__)) + '/RSAKEY.pem'
with open(fullpath, 'r') as f:
key = f.read()
RSAKey(key=key).save()
def is_code_valid(url, user, client): def is_code_valid(url, user, client):
""" """
Check if the code inside the url is valid. Check if the code inside the url is valid.

View file

@ -6,6 +6,7 @@ import uuid
from django.contrib.auth import REDIRECT_FIELD_NAME from django.contrib.auth import REDIRECT_FIELD_NAME
from django.contrib.auth.models import AnonymousUser from django.contrib.auth.models import AnonymousUser
from django.core.management import call_command
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.test import RequestFactory from django.test import RequestFactory
from django.test import TestCase from django.test import TestCase
@ -22,11 +23,35 @@ class AuthorizationCodeFlowTestCase(TestCase):
""" """
def setUp(self): def setUp(self):
call_command('creatersakey')
self.factory = RequestFactory() self.factory = RequestFactory()
self.user = create_fake_user() self.user = create_fake_user()
self.client = create_fake_client(response_type='code') self.client = create_fake_client(response_type='code')
self.client_public = create_fake_client(response_type='code', is_public=True) self.client_public = create_fake_client(response_type='code', is_public=True)
self.client_implicit = create_fake_client(response_type='id_token token')
self.state = uuid.uuid4().hex self.state = uuid.uuid4().hex
self.nonce = uuid.uuid4().hex
def _auth_request(self, method, params_or_data={}, is_user_authenticated=False):
url = reverse('oidc_provider:authorize')
if method.lower() == 'get':
query_str = urlencode(params_or_data).replace('+', '%20')
if query_str:
url += '?' + query_str
request = self.factory.get(url)
elif method.lower() == 'post':
request = self.factory.post(url, data=params_or_data)
else:
raise Exception('Method unsupported for an Authorization Request.')
# Simulate that the user is logged.
request.user = self.user if is_user_authenticated else AnonymousUser()
response = AuthorizeView.as_view()(request)
return response
def test_missing_parameters(self): def test_missing_parameters(self):
""" """
@ -36,11 +61,7 @@ class AuthorizationCodeFlowTestCase(TestCase):
See: https://tools.ietf.org/html/rfc6749#section-4.1.2.1 See: https://tools.ietf.org/html/rfc6749#section-4.1.2.1
""" """
url = reverse('oidc_provider:authorize') response = self._auth_request('get')
request = self.factory.get(url)
response = AuthorizeView.as_view()(request)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual(bool(response.content), True) self.assertEqual(bool(response.content), True)
@ -53,19 +74,15 @@ class AuthorizationCodeFlowTestCase(TestCase):
See: http://openid.net/specs/openid-connect-core-1_0.html#AuthError See: http://openid.net/specs/openid-connect-core-1_0.html#AuthError
""" """
# Create an authorize request with an unsupported response_type. # Create an authorize request with an unsupported response_type.
query_str = urlencode({ params = {
'client_id': self.client.client_id, 'client_id': self.client.client_id,
'response_type': 'something_wrong', 'response_type': 'something_wrong',
'redirect_uri': self.client.default_redirect_uri, 'redirect_uri': self.client.default_redirect_uri,
'scope': 'openid email', 'scope': 'openid email',
'state': self.state, 'state': self.state,
}).replace('+', '%20') }
url = reverse('oidc_provider:authorize') + '?' + query_str response = self._auth_request('get', params)
request = self.factory.get(url)
response = AuthorizeView.as_view()(request)
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
self.assertEqual(response.has_header('Location'), True) self.assertEqual(response.has_header('Location'), True)
@ -81,34 +98,20 @@ class AuthorizationCodeFlowTestCase(TestCase):
See: http://openid.net/specs/openid-connect-core-1_0.html#Authenticates See: http://openid.net/specs/openid-connect-core-1_0.html#Authenticates
""" """
query_str = urlencode({ params = {
'client_id': self.client.client_id, 'client_id': self.client.client_id,
'response_type': 'code', 'response_type': 'code',
'redirect_uri': self.client.default_redirect_uri, 'redirect_uri': self.client.default_redirect_uri,
'scope': 'openid email', 'scope': 'openid email',
'state': self.state, 'state': self.state,
}).replace('+', '%20') }
url = reverse('oidc_provider:authorize') + '?' + query_str response = self._auth_request('get', params)
request = self.factory.get(url)
request.user = AnonymousUser()
response = AuthorizeView.as_view()(request)
# Check if user was redirected to the login view. # Check if user was redirected to the login view.
login_url_exists = settings.get('LOGIN_URL') in response['Location'] login_url_exists = settings.get('LOGIN_URL') in response['Location']
self.assertEqual(login_url_exists, True) self.assertEqual(login_url_exists, True)
# Check if the login will redirect to a valid url.
try:
next_value = response['Location'].split(REDIRECT_FIELD_NAME + '=')[1]
next_url = unquote(next_value)
is_next_ok = next_url == url
except:
is_next_ok = False
self.assertEqual(is_next_ok, True)
def test_user_consent_inputs(self): def test_user_consent_inputs(self):
""" """
Once the End-User is authenticated, the Authorization Server MUST Once the End-User is authenticated, the Authorization Server MUST
@ -117,7 +120,7 @@ class AuthorizationCodeFlowTestCase(TestCase):
See: http://openid.net/specs/openid-connect-core-1_0.html#Consent See: http://openid.net/specs/openid-connect-core-1_0.html#Consent
""" """
query_str = urlencode({ params = {
'client_id': self.client.client_id, 'client_id': self.client.client_id,
'response_type': 'code', 'response_type': 'code',
'redirect_uri': self.client.default_redirect_uri, 'redirect_uri': self.client.default_redirect_uri,
@ -126,15 +129,9 @@ class AuthorizationCodeFlowTestCase(TestCase):
# PKCE parameters. # PKCE parameters.
'code_challenge': FAKE_CODE_CHALLENGE, 'code_challenge': FAKE_CODE_CHALLENGE,
'code_challenge_method': 'S256', 'code_challenge_method': 'S256',
}).replace('+', '%20') }
url = reverse('oidc_provider:authorize') + '?' + query_str response = self._auth_request('get', params, is_user_authenticated=True)
request = self.factory.get(url)
# Simulate that the user is logged.
request.user = self.user
response = AuthorizeView.as_view()(request)
# Check if hidden inputs exists in the form, # Check if hidden inputs exists in the form,
# also if their values are valid. # also if their values are valid.
@ -165,14 +162,10 @@ class AuthorizationCodeFlowTestCase(TestCase):
the parameters defined in Section 4.1.2 of OAuth 2.0 [RFC6749] the parameters defined in Section 4.1.2 of OAuth 2.0 [RFC6749]
by adding them as query parameters to the redirect_uri. by adding them as query parameters to the redirect_uri.
""" """
response_type = 'code' data = {
url = reverse('oidc_provider:authorize')
post_data = {
'client_id': self.client.client_id, 'client_id': self.client.client_id,
'redirect_uri': self.client.default_redirect_uri, 'redirect_uri': self.client.default_redirect_uri,
'response_type': response_type, 'response_type': 'code',
'scope': 'openid email', 'scope': 'openid email',
'state': self.state, 'state': self.state,
# PKCE parameters. # PKCE parameters.
@ -180,11 +173,7 @@ class AuthorizationCodeFlowTestCase(TestCase):
'code_challenge_method': 'S256', 'code_challenge_method': 'S256',
} }
request = self.factory.post(url, data=post_data) response = self._auth_request('post', data, is_user_authenticated=True)
# Simulate that the user is logged.
request.user = self.user
response = AuthorizeView.as_view()(request)
# Because user doesn't allow app, SHOULD exists an error parameter # Because user doesn't allow app, SHOULD exists an error parameter
# in the query. # in the query.
@ -194,13 +183,9 @@ class AuthorizationCodeFlowTestCase(TestCase):
msg='"access_denied" code is missing in query.') msg='"access_denied" code is missing in query.')
# Simulate user authorization. # Simulate user authorization.
post_data['allow'] = 'Accept' # Should be the value of the button. data['allow'] = 'Accept' # Will be the value of the button.
request = self.factory.post(url, data=post_data) response = self._auth_request('post', data, is_user_authenticated=True)
# Simulate that the user is logged.
request.user = self.user
response = AuthorizeView.as_view()(request)
is_code_ok = is_code_valid(url=response['Location'], is_code_ok = is_code_valid(url=response['Location'],
user=self.user, user=self.user,
@ -219,7 +204,7 @@ class AuthorizationCodeFlowTestCase(TestCase):
list of scopes) and because they might be prompted for the same list of scopes) and because they might be prompted for the same
authorization multiple times, the server skip it. authorization multiple times, the server skip it.
""" """
post_data = { data = {
'client_id': self.client.client_id, 'client_id': self.client.client_id,
'redirect_uri': self.client.default_redirect_uri, 'redirect_uri': self.client.default_redirect_uri,
'response_type': 'code', 'response_type': 'code',
@ -229,34 +214,25 @@ class AuthorizationCodeFlowTestCase(TestCase):
} }
request = self.factory.post(reverse('oidc_provider:authorize'), request = self.factory.post(reverse('oidc_provider:authorize'),
data=post_data) data=data)
# Simulate that the user is logged. # Simulate that the user is logged.
request.user = self.user request.user = self.user
with self.settings(OIDC_SKIP_CONSENT_ALWAYS=True): with self.settings(OIDC_SKIP_CONSENT_ALWAYS=True):
response = AuthorizeView.as_view()(request) response = self._auth_request('post', data, is_user_authenticated=True)
self.assertEqual('code' in response['Location'], True, self.assertEqual('code' in response['Location'], True,
msg='Code is missing in the returned url.') msg='Code is missing in the returned url.')
response = AuthorizeView.as_view()(request) response = self._auth_request('post', data, is_user_authenticated=True)
is_code_ok = is_code_valid(url=response['Location'], is_code_ok = is_code_valid(url=response['Location'],
user=self.user, user=self.user,
client=self.client) client=self.client)
self.assertEqual(is_code_ok, True, msg='Code returned is invalid.') self.assertEqual(is_code_ok, True, msg='Code returned is invalid.')
del post_data['allow'] del data['allow']
query_str = urlencode(post_data).replace('+', '%20') response = self._auth_request('get', data, is_user_authenticated=True)
url = reverse('oidc_provider:authorize') + '?' + query_str
request = self.factory.get(url)
# Simulate that the user is logged.
request.user = self.user
# Ensure user consent skip is enabled.
response = AuthorizeView.as_view()(request)
is_code_ok = is_code_valid(url=response['Location'], is_code_ok = is_code_valid(url=response['Location'],
user=self.user, user=self.user,
@ -264,10 +240,7 @@ class AuthorizationCodeFlowTestCase(TestCase):
self.assertEqual(is_code_ok, True, msg='Code returned is invalid or missing.') self.assertEqual(is_code_ok, True, msg='Code returned is invalid or missing.')
def test_response_uri_is_properly_constructed(self): def test_response_uri_is_properly_constructed(self):
""" data = {
TODO
"""
post_data = {
'client_id': self.client.client_id, 'client_id': self.client.client_id,
'redirect_uri': self.client.default_redirect_uri + "?redirect_state=xyz", 'redirect_uri': self.client.default_redirect_uri + "?redirect_state=xyz",
'response_type': 'code', 'response_type': 'code',
@ -276,123 +249,59 @@ class AuthorizationCodeFlowTestCase(TestCase):
'allow': 'Accept', 'allow': 'Accept',
} }
request = self.factory.post(reverse('oidc_provider:authorize'), response = self._auth_request('post', data, is_user_authenticated=True)
data=post_data)
# Simulate that the user is logged.
request.user = self.user
response = AuthorizeView.as_view()(request) # TODO
is_code_ok = is_code_valid(url=response['Location'],
user=self.user,
client=self.client)
self.assertEqual(is_code_ok, True,
msg='Code returned is invalid.')
def test_scope_with_plus(self):
"""
In query string, scope use `+` instead of the space url-encoded.
"""
scope_test = 'openid email profile'
query_str = urlencode({
'client_id': self.client.client_id,
'response_type': 'code',
'redirect_uri': self.client.default_redirect_uri,
'scope': scope_test,
'state': self.state,
})
url = reverse('oidc_provider:authorize') + '?' + query_str
request = self.factory.get(url)
# Simulate that the user is logged.
request.user = self.user
response = AuthorizeView.as_view()(request)
# Search the scopes in the html.
self.assertEqual(scope_test in response.content.decode('utf-8'), True)
def test_public_client_auto_approval(self): def test_public_client_auto_approval(self):
""" """
It's recommended not auto-approving requests for non-confidential clients. It's recommended not auto-approving requests for non-confidential clients.
""" """
query_str = urlencode({ params = {
'client_id': self.client_public.client_id, 'client_id': self.client_public.client_id,
'response_type': 'code', 'response_type': 'code',
'redirect_uri': self.client_public.default_redirect_uri, 'redirect_uri': self.client_public.default_redirect_uri,
'scope': 'openid email', 'scope': 'openid email',
'state': self.state, 'state': self.state,
}) }
url = reverse('oidc_provider:authorize') + '?' + query_str
request = self.factory.get(url)
# Simulate that the user is logged.
request.user = self.user
with self.settings(OIDC_SKIP_CONSENT_ALWAYS=True): with self.settings(OIDC_SKIP_CONSENT_ALWAYS=True):
response = AuthorizeView.as_view()(request) response = self._auth_request('get', params, is_user_authenticated=True)
self.assertEqual('Request for Permission' in response.content.decode('utf-8'), True) self.assertEqual('Request for Permission' in response.content.decode('utf-8'), True)
class ImplicitFlowTestCase(TestCase): def test_implicit_missing_nonce(self):
"""
Test cases for Authorize Endpoint using Implicit Grant Flow.
"""
def setUp(self):
self.factory = RequestFactory()
self.user = create_fake_user()
self.client = create_fake_client(response_type='id_token token')
self.state = uuid.uuid4().hex
self.nonce = uuid.uuid4().hex
create_rsakey()
def test_missing_nonce(self):
""" """
The `nonce` parameter is REQUIRED if you use the Implicit Flow. The `nonce` parameter is REQUIRED if you use the Implicit Flow.
""" """
query_str = urlencode({ params = {
'client_id': self.client.client_id, 'client_id': self.client_implicit.client_id,
'response_type': self.client.response_type, 'response_type': self.client_implicit.response_type,
'redirect_uri': self.client.default_redirect_uri, 'redirect_uri': self.client_implicit.default_redirect_uri,
'scope': 'openid email', 'scope': 'openid email',
'state': self.state, 'state': self.state,
}).replace('+', '%20') }
url = reverse('oidc_provider:authorize') + '?' + query_str response = self._auth_request('get', params, is_user_authenticated=True)
request = self.factory.get(url)
# Simulate that the user is logged.
request.user = self.user
response = AuthorizeView.as_view()(request)
self.assertEqual('#error=invalid_request' in response['Location'], True) self.assertEqual('#error=invalid_request' in response['Location'], True)
def test_access_token_response(self): def test_implicit_access_token_response(self):
""" """
Unlike the Authorization Code flow, in which the client makes Unlike the Authorization Code flow, in which the client makes
separate requests for authorization and for an access token, the client separate requests for authorization and for an access token, the client
receives the access token as the result of the authorization request. receives the access token as the result of the authorization request.
""" """
post_data = { data = {
'client_id': self.client.client_id, 'client_id': self.client_implicit.client_id,
'redirect_uri': self.client.default_redirect_uri, 'redirect_uri': self.client_implicit.default_redirect_uri,
'response_type': self.client.response_type, 'response_type': self.client_implicit.response_type,
'scope': 'openid email', 'scope': 'openid email',
'state': self.state, 'state': self.state,
'nonce': self.nonce, 'nonce': self.nonce,
'allow': 'Accept', 'allow': 'Accept',
} }
request = self.factory.post(reverse('oidc_provider:authorize'), response = self._auth_request('post', data, is_user_authenticated=True)
data=post_data)
# Simulate that the user is logged.
request.user = self.user
response = AuthorizeView.as_view()(request)
self.assertEqual('access_token' in response['Location'], True) self.assertEqual('access_token' in response['Location'], True)

View file

@ -4,6 +4,7 @@ try:
except ImportError: except ImportError:
from urllib import urlencode from urllib import urlencode
from django.core.management import call_command
from django.test import RequestFactory, override_settings from django.test import RequestFactory, override_settings
from django.test import TestCase from django.test import TestCase
from jwkest.jwk import KEYS from jwkest.jwk import KEYS
@ -23,10 +24,10 @@ class TokenTestCase(TestCase):
""" """
def setUp(self): def setUp(self):
call_command('creatersakey')
self.factory = RequestFactory() self.factory = RequestFactory()
self.user = create_fake_user() self.user = create_fake_user()
self.client = create_fake_client(response_type='code') self.client = create_fake_client(response_type='code')
create_rsakey()
def _auth_code_post_data(self, code): def _auth_code_post_data(self, code):
""" """