Skip to content
This repository has been archived by the owner on Dec 6, 2024. It is now read-only.

Commit

Permalink
Merge pull request #18 from tobias-reese/feature/ImplementImplicitFlow
Browse files Browse the repository at this point in the history
Feature/implement implicit flow
  • Loading branch information
Rafael Muñoz Cárdenas authored Feb 8, 2019
2 parents 3bcce0d + f0bab46 commit 7a63810
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 41 deletions.
4 changes: 2 additions & 2 deletions oauth2_provider_jwt/urls.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from django.conf.urls import url
from oauth2_provider import views

from .views import TokenView
from .views import TokenView, JWTAuthorizationView

app_name = "oauth2_provider_jwt"

urlpatterns = [
url(r"^authorize/$", views.AuthorizationView.as_view(), name="authorize"),
url(r"^authorize/$", JWTAuthorizationView.as_view(), name="authorize"),
url(r"^token/$", TokenView.as_view(), name="token"),
url(r"^revoke_token/$", views.RevokeTokenView.as_view(),
name="revoke-token"),
Expand Down
42 changes: 32 additions & 10 deletions oauth2_provider_jwt/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,16 @@
import json
import logging

try:
from urllib.parse import urlencode, urlparse, parse_qs
except ImportError:
from urllib import urlencode # noqa
from urlparse import urlparse, parse_qs

from django.conf import settings
from django.utils.module_loading import import_string
from oauth2_provider import views
from oauth2_provider.http import OAuth2ResponseRedirect
from oauth2_provider.models import get_access_token_model

from .utils import generate_payload, encode_jwt
Expand All @@ -16,6 +23,27 @@ class WrongUsername(Exception):
pass


class JWTAuthorizationView(views.AuthorizationView):

def get(self, request, *args, **kwargs):
response = super(JWTAuthorizationView, self).get(request, *args,
**kwargs)
if request.GET.get('response_type', None) == 'token' \
and response.status_code == 302:
url = urlparse(response.url)
params = parse_qs(url.fragment)
content = {
'access_token': params['access_token'][0],
'expires_in': int(params['expires_in'][0]),
'scope': params['scope'][0]
}
jwt = TokenView()._get_access_token_jwt(request, content)
response = OAuth2ResponseRedirect(
'{}&access_token_jwt={}'.format(response.url, jwt),
response.allowed_schemes)
return response


class TokenView(views.TokenView):
def _get_access_token_jwt(self, request, content):
extra_data = {}
Expand All @@ -28,16 +56,10 @@ def _get_access_token_jwt(self, request, content):
if 'scope' in content:
extra_data['scope'] = content['scope']

username = request.POST.get('username')
if username:
# HACK: The only way to verify the username is to check the token.
# This means an extra wasted database call
token = get_access_token_model().objects.get(
token=content['access_token']
)
if token.user.get_username() != username:
raise WrongUsername()
extra_data['username'] = username
token = get_access_token_model().objects.get(
token=content['access_token']
)
extra_data['username'] = token.user.username

payload = generate_payload(issuer, content['expires_in'], **extra_data)
token = encode_jwt(payload)
Expand Down
49 changes: 20 additions & 29 deletions tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
import re

try:
from urllib.parse import urlencode
from urllib.parse import urlencode, urlparse, parse_qs
except ImportError:
from urllib import urlencode # noqa
from urllib import urlencode # noqa
from urlparse import urlparse, parse_qs
try:
from unittest.mock import patch
except ImportError:
Expand Down Expand Up @@ -170,47 +171,37 @@ def test_get_token_authorization_code(self):
self.assertEqual('test_user', payload_content['username'])
self.assertEqual('read write', payload_content['scope'])

def test_get_token_authorization_code_wrong_user(self):
def test_get_token_implicit(self):
"""
Fix for https://github.com/Humanitec/django-oauth-toolkit-jwt/issues/14
Request an access token using Implicit Flow
"""
Application.objects.create(
client_id='user_app_id',
client_secret='user_app_secret',
client_type=Application.CLIENT_CONFIDENTIAL,
authorization_grant_type=Application.GRANT_AUTHORIZATION_CODE,
authorization_grant_type=Application.GRANT_IMPLICIT,
name='user app',
skip_authorization=True,
redirect_uris='http://localhost:8002/callback',
)

self.client.force_login(self.test_user)
response = self.client.get(reverse("oauth2_provider_jwt:authorize") +
'?response_type=code&client_id=user_app_id')

response = self.client.get(
reverse("oauth2_provider_jwt:authorize") +
'?response_type=token&client_id=user_app_id')
self.assertEqual(302, response.status_code)
match = re.match(r'http://localhost:8002/callback\?code=(\w+)',
response.url)
self.assertIsNotNone(match)
code = match.group(1)
url = urlparse(response.url)
params = parse_qs(url.fragment)
self.assertEqual('Bearer', params['token_type'][0])
self.assertEqual('read write', params['scope'][0])

# To simulate that the token call is normally made unauthenticated
self.client.logout()
data = {
'client_id': 'user_app_id',
'client_secret': 'user_app_secret',
'code': code,
'grant_type': 'authorization_code',
'redirect_uri': 'http://localhost:8002/callback',
'username': 'some_fake_user', # Pass in wrong user
}
response = self.client.post(reverse("oauth2_provider_jwt:token"), data)
self.assertEqual(400, response.status_code)
self.assertEqual({
"error": "invalid_request",
"error_description": "Request username doesn't match "
"username in original authorize",
}, response.json())
self.assertTrue(params['access_token'][0])
access_token_jwt = params['access_token_jwt'][0]
self.assertTrue(access_token_jwt)

payload_content = self.decode_jwt(access_token_jwt)
self.assertEqual('test_user', payload_content['username'])
self.assertEqual('read write', payload_content['scope'])

@patch('oauth2_provider_jwt.views.TokenView._is_jwt_config_set')
def test_do_not_get_token_missing_conf(self, mock_is_jwt_config_set):
Expand Down

0 comments on commit 7a63810

Please sign in to comment.