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.name = 'Some Client'
client.client_id = str(random.randint(1, 999999)).zfill(6)
if is_public:
client.client_type = 'public'
client.client_id = 'p123'
client.client_secret = ''
else:
client.client_id = 'c123'
client.client_secret = '456'
client.client_secret = str(random.randint(1, 999999)).zfill(6)
client.response_type = response_type
client.redirect_uris = ['http://example.com/']
@ -57,17 +56,6 @@ def create_fake_client(response_type, is_public=False):
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):
"""
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.models import AnonymousUser
from django.core.management import call_command
from django.core.urlresolvers import reverse
from django.test import RequestFactory
from django.test import TestCase
@ -22,11 +23,35 @@ class AuthorizationCodeFlowTestCase(TestCase):
"""
def setUp(self):
call_command('creatersakey')
self.factory = RequestFactory()
self.user = create_fake_user()
self.client = create_fake_client(response_type='code')
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.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):
"""
@ -36,11 +61,7 @@ class AuthorizationCodeFlowTestCase(TestCase):
See: https://tools.ietf.org/html/rfc6749#section-4.1.2.1
"""
url = reverse('oidc_provider:authorize')
request = self.factory.get(url)
response = AuthorizeView.as_view()(request)
response = self._auth_request('get')
self.assertEqual(response.status_code, 200)
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
"""
# Create an authorize request with an unsupported response_type.
query_str = urlencode({
params = {
'client_id': self.client.client_id,
'response_type': 'something_wrong',
'redirect_uri': self.client.default_redirect_uri,
'scope': 'openid email',
'state': self.state,
}).replace('+', '%20')
}
url = reverse('oidc_provider:authorize') + '?' + query_str
request = self.factory.get(url)
response = AuthorizeView.as_view()(request)
response = self._auth_request('get', params)
self.assertEqual(response.status_code, 302)
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
"""
query_str = urlencode({
params = {
'client_id': self.client.client_id,
'response_type': 'code',
'redirect_uri': self.client.default_redirect_uri,
'scope': 'openid email',
'state': self.state,
}).replace('+', '%20')
}
url = reverse('oidc_provider:authorize') + '?' + query_str
request = self.factory.get(url)
request.user = AnonymousUser()
response = AuthorizeView.as_view()(request)
response = self._auth_request('get', params)
# Check if user was redirected to the login view.
login_url_exists = settings.get('LOGIN_URL') in response['Location']
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):
"""
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
"""
query_str = urlencode({
params = {
'client_id': self.client.client_id,
'response_type': 'code',
'redirect_uri': self.client.default_redirect_uri,
@ -126,15 +129,9 @@ class AuthorizationCodeFlowTestCase(TestCase):
# PKCE parameters.
'code_challenge': FAKE_CODE_CHALLENGE,
'code_challenge_method': 'S256',
}).replace('+', '%20')
}
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)
response = self._auth_request('get', params, is_user_authenticated=True)
# Check if hidden inputs exists in the form,
# 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]
by adding them as query parameters to the redirect_uri.
"""
response_type = 'code'
url = reverse('oidc_provider:authorize')
post_data = {
data = {
'client_id': self.client.client_id,
'redirect_uri': self.client.default_redirect_uri,
'response_type': response_type,
'response_type': 'code',
'scope': 'openid email',
'state': self.state,
# PKCE parameters.
@ -180,11 +173,7 @@ class AuthorizationCodeFlowTestCase(TestCase):
'code_challenge_method': 'S256',
}
request = self.factory.post(url, data=post_data)
# Simulate that the user is logged.
request.user = self.user
response = AuthorizeView.as_view()(request)
response = self._auth_request('post', data, is_user_authenticated=True)
# Because user doesn't allow app, SHOULD exists an error parameter
# in the query.
@ -194,13 +183,9 @@ class AuthorizationCodeFlowTestCase(TestCase):
msg='"access_denied" code is missing in query.')
# 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)
# Simulate that the user is logged.
request.user = self.user
response = AuthorizeView.as_view()(request)
response = self._auth_request('post', data, is_user_authenticated=True)
is_code_ok = is_code_valid(url=response['Location'],
user=self.user,
@ -219,7 +204,7 @@ class AuthorizationCodeFlowTestCase(TestCase):
list of scopes) and because they might be prompted for the same
authorization multiple times, the server skip it.
"""
post_data = {
data = {
'client_id': self.client.client_id,
'redirect_uri': self.client.default_redirect_uri,
'response_type': 'code',
@ -229,34 +214,25 @@ class AuthorizationCodeFlowTestCase(TestCase):
}
request = self.factory.post(reverse('oidc_provider:authorize'),
data=post_data)
data=data)
# Simulate that the user is logged.
request.user = self.user
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,
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'],
user=self.user,
client=self.client)
self.assertEqual(is_code_ok, True, msg='Code returned is invalid.')
del post_data['allow']
query_str = urlencode(post_data).replace('+', '%20')
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)
del data['allow']
response = self._auth_request('get', data, is_user_authenticated=True)
is_code_ok = is_code_valid(url=response['Location'],
user=self.user,
@ -264,10 +240,7 @@ class AuthorizationCodeFlowTestCase(TestCase):
self.assertEqual(is_code_ok, True, msg='Code returned is invalid or missing.')
def test_response_uri_is_properly_constructed(self):
"""
TODO
"""
post_data = {
data = {
'client_id': self.client.client_id,
'redirect_uri': self.client.default_redirect_uri + "?redirect_state=xyz",
'response_type': 'code',
@ -276,123 +249,59 @@ class AuthorizationCodeFlowTestCase(TestCase):
'allow': 'Accept',
}
request = self.factory.post(reverse('oidc_provider:authorize'),
data=post_data)
# Simulate that the user is logged.
request.user = self.user
response = self._auth_request('post', data, is_user_authenticated=True)
response = AuthorizeView.as_view()(request)
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)
# TODO
def test_public_client_auto_approval(self):
"""
It's recommended not auto-approving requests for non-confidential clients.
"""
query_str = urlencode({
params = {
'client_id': self.client_public.client_id,
'response_type': 'code',
'redirect_uri': self.client_public.default_redirect_uri,
'scope': 'openid email',
'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):
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)
class ImplicitFlowTestCase(TestCase):
"""
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):
def test_implicit_missing_nonce(self):
"""
The `nonce` parameter is REQUIRED if you use the Implicit Flow.
"""
query_str = urlencode({
'client_id': self.client.client_id,
'response_type': self.client.response_type,
'redirect_uri': self.client.default_redirect_uri,
params = {
'client_id': self.client_implicit.client_id,
'response_type': self.client_implicit.response_type,
'redirect_uri': self.client_implicit.default_redirect_uri,
'scope': 'openid email',
'state': self.state,
}).replace('+', '%20')
}
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)
response = self._auth_request('get', params, is_user_authenticated=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
separate requests for authorization and for an access token, the client
receives the access token as the result of the authorization request.
"""
post_data = {
'client_id': self.client.client_id,
'redirect_uri': self.client.default_redirect_uri,
'response_type': self.client.response_type,
data = {
'client_id': self.client_implicit.client_id,
'redirect_uri': self.client_implicit.default_redirect_uri,
'response_type': self.client_implicit.response_type,
'scope': 'openid email',
'state': self.state,
'nonce': self.nonce,
'allow': 'Accept',
}
request = self.factory.post(reverse('oidc_provider:authorize'),
data=post_data)
# Simulate that the user is logged.
request.user = self.user
response = AuthorizeView.as_view()(request)
response = self._auth_request('post', data, is_user_authenticated=True)
self.assertEqual('access_token' in response['Location'], True)

View file

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