Skip to content

Commit

Permalink
remove implicit grant type for OAuth 2 apps
Browse files Browse the repository at this point in the history
  • Loading branch information
rooftopcellist committed May 29, 2019
1 parent 41f2b83 commit cb27984
Show file tree
Hide file tree
Showing 7 changed files with 28 additions and 97 deletions.
4 changes: 2 additions & 2 deletions awx/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1108,7 +1108,7 @@ def create(self, validated_data):
)
obj = super(UserAuthorizedTokenSerializer, self).create(validated_data)
obj.save()
if obj.application and obj.application.authorization_grant_type != 'implicit':
if obj.application:
RefreshToken.objects.create(
user=current_user,
token=generate_token(),
Expand All @@ -1130,7 +1130,7 @@ def create(self, validated_data):
if obj.application and obj.application.user:
obj.user = obj.application.user
obj.save()
if obj.application and obj.application.authorization_grant_type != 'implicit':
if obj.application:
RefreshToken.objects.create(
user=current_user,
token=generate_token(),
Expand Down
11 changes: 0 additions & 11 deletions awx/api/templates/api/api_o_auth_authorization_root_view.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,6 @@ to the redirect_uri specified in the application. The client application will th
AWX will respond with the `access_token`, `token_type`, `refresh_token`, and `expires_in`. For more
information on testing this flow, refer to [django-oauth-toolkit](http://django-oauth-toolkit.readthedocs.io/en/latest/tutorial/tutorial_01.html#test-your-authorization-server).

## Create Token for an Application using Implicit grant type
Suppose we have an application "admin's app" of grant type `implicit`.
In API browser, first make sure the user is logged in via session auth, then visit authorization
endpoint with given parameters:
```text
http://localhost:8013/api/o/authorize/?response_type=token&client_id=L0uQQWW8pKX51hoqIRQGsuqmIdPi2AcXZ9EJRGmj&scope=read
```
Here the value of `client_id` should be the same as that of `client_id` field of underlying application.
On success, an authorization page should be displayed asking the logged in user to grant/deny the access token.
Once the user clicks on 'grant', the API browser will try POSTing to the same endpoint with the same parameters
in POST body, on success a 302 redirect will be returned.

## Create Token for an Application using Password grant type

Expand Down
20 changes: 20 additions & 0 deletions awx/main/migrations/0079_v360_rm_implicit_oauth2_apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-05-28 17:15
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('main', '0078_v360_clear_sessions_tokens_jt'),
]

operations = [
migrations.AlterField(
model_name='oauth2application',
name='authorization_grant_type',
field=models.CharField(choices=[('authorization-code', 'Authorization code'), ('password', 'Resource owner password-based')], help_text='The Grant type the user must use for acquire tokens for this application.', max_length=32),
),
]
2 changes: 0 additions & 2 deletions awx/main/models/oauth.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,9 @@ class Meta:
)

GRANT_AUTHORIZATION_CODE = "authorization-code"
GRANT_IMPLICIT = "implicit"
GRANT_PASSWORD = "password"
GRANT_TYPES = (
(GRANT_AUTHORIZATION_CODE, _("Authorization code")),
(GRANT_IMPLICIT, _("Implicit")),
(GRANT_PASSWORD, _("Resource owner password-based")),
)

Expand Down
40 changes: 5 additions & 35 deletions awx/main/tests/functional/api/test_oauth.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

from django.db import connection
from django.test.utils import override_settings
from django.test import Client
from django.utils.encoding import smart_str, smart_bytes

from awx.main.utils.encryption import decrypt_value, get_encryption_key
Expand Down Expand Up @@ -114,7 +113,7 @@ def test_oauth_application_update(oauth_application, organization, patch, admin,
'name': 'Test app with immutable grant type and user',
'organization': organization.pk,
'redirect_uris': 'http://localhost/api/',
'authorization_grant_type': 'implicit',
'authorization_grant_type': 'password',
'skip_authorization': True,
}, admin, expect=200
)
Expand Down Expand Up @@ -175,27 +174,22 @@ def test_oauth_token_create(oauth_application, get, post, admin):
assert response.data['summary_fields']['tokens']['results'][0] == {
'id': token.pk, 'scope': token.scope, 'token': '************'
}
# If the application is implicit grant type, no new refresb tokens should be created.
# The following tests check for that.
oauth_application.authorization_grant_type = 'implicit'
oauth_application.save()
token_count = RefreshToken.objects.count()

response = post(
reverse('api:o_auth2_token_list'),
{'scope': 'read', 'application': oauth_application.pk}, admin, expect=201
)
assert response.data['refresh_token'] is None
assert response.data['refresh_token']
response = post(
reverse('api:user_authorized_token_list', kwargs={'pk': admin.pk}),
{'scope': 'read', 'application': oauth_application.pk}, admin, expect=201
)
assert response.data['refresh_token'] is None
assert response.data['refresh_token']
response = post(
reverse('api:application_o_auth2_token_list', kwargs={'pk': oauth_application.pk}),
{'scope': 'read'}, admin, expect=201
)
assert response.data['refresh_token'] is None
assert token_count == RefreshToken.objects.count()
assert response.data['refresh_token']


@pytest.mark.django_db
Expand Down Expand Up @@ -260,30 +254,6 @@ def test_oauth_list_user_tokens(oauth_application, post, get, admin, alice):
post(url, {'scope': 'read'}, user, expect=201)
response = get(url, admin, expect=200)
assert response.data['count'] == 1


@pytest.mark.django_db
def test_implicit_authorization(oauth_application, admin):
oauth_application.client_type = 'confidential'
oauth_application.authorization_grant_type = 'implicit'
oauth_application.redirect_uris = 'http://test.com'
oauth_application.save()
data = {
'response_type': 'token',
'client_id': oauth_application.client_id,
'client_secret': oauth_application.client_secret,
'scope': 'read',
'redirect_uri': 'http://test.com',
'allow': True
}

request_client = Client()
request_client.force_login(admin, 'django.contrib.auth.backends.ModelBackend')
refresh_token_count = RefreshToken.objects.count()
response = request_client.post(drf_reverse('api:authorize'), data)
assert 'http://test.com' in response.url and 'access_token' in response.url
# Make sure no refresh token is created for app with implicit grant type.
assert refresh_token_count == RefreshToken.objects.count()


@pytest.mark.django_db
Expand Down
1 change: 0 additions & 1 deletion awx/ui/test/e2e/objects/applications.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ const addEditElements = {

const authorizationGrantTypeOptions = {
authorizationCode: 'Authorization code',
implicit: 'Implicit',
resourceOwnerPasswordBased: 'Resource owner password-based',
};

Expand Down
47 changes: 1 addition & 46 deletions docs/auth/oauth.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ This page lists OAuth 2 utility endpoints used for authorization, token refresh
Note endpoints other than `/api/o/authorize/` are not meant to be used in browsers and do not
support HTTP GET. The endpoints here strictly follow
[RFC specs for OAuth 2](https://tools.ietf.org/html/rfc6749), so please use that for detailed
reference. The `implicit` grant type can only be used to acquire a access token if the user is already logged in via session authentication, as that confirms that the user is authorized to create an access token. Here we give some examples to demonstrate the typical usage of these endpoints in
reference. Here we give some examples to demonstrate the typical usage of these endpoints in
AWX context (Note AWX net location default to `http://localhost:8013` in examples):


Expand Down Expand Up @@ -265,51 +265,6 @@ AWX will respond with the `access_token`, `token_type`, `refresh_token`, and `ex
information on testing this flow, refer to [django-oauth-toolkit](http://django-oauth-toolkit.readthedocs.io/en/latest/tutorial/tutorial_01.html#test-your-authorization-server).



#### Application using `implicit` grant type
The use case: single page web apps that can't keep a client_secret as secure. This method with skips the
authorization code part of the flow and just returns an access token.
Suppose we have an application `admin's app` of grant type `implicit`:
```text
{
"id": 1,
"type": "application",
"related": {
...
"name": "admin's app",
"user": 1,
"client_id": "L0uQQWW8pKX51hoqIRQGsuqmIdPi2AcXZ9EJRGmj",
"client_secret": "9Wp4dUrUsigI8J15fQYJ3jn0MJHLkAjyw7ikBsABeWTNJbZwy7eB2Xro9ykYuuygerTPQ2gIF2DCTtN3kurkt0Me3AhanEw6peRNvNLs1NNfI4f53mhX8zo5JQX0BKy5",
"client_type": "confidential",
"redirect_uris": "http://<awx>/api/",
"authorization_grant_type": "implicit",
"skip_authorization": false
}
```

In API browser, first make sure the user is logged in via session auth, then visit authorization
endpoint with given parameters:
```text
http://localhost:8013/api/o/authorize/?response_type=token&client_id=L0uQQWW8pKX51hoqIRQGsuqmIdPi2AcXZ9EJRGmj&scope=read
```
Here the value of `client_id` should be the same as that of `client_id` field of underlying application.
On success, an authorization page should be displayed asking the logged in user to grant/deny the access token.
Once the user clicks on 'grant', the API browser will try POSTing to the same endpoint with the same parameters in POST body, on success a 302 redirect will be returned:
```text
HTTP/1.1 302 Found
Connection:keep-alive
Content-Language:en
Content-Length:0
Content-Type:text/html; charset=utf-8
Date:Tue, 05 Dec 2017 20:36:19 GMT
Location:http://localhost:8013/api/#access_token=0lVJJkolFTwYawHyGkk7NTmSKdzBen&token_type=Bearer&state=&expires_in=315360000000&scope=read
Server:nginx/1.12.2
Strict-Transport-Security:max-age=15768000
Vary:Accept-Language, Cookie
```


#### Application using `password` grant type
This is also called the `resource owner credentials grant`. This is for use by users who have
native access to the web app. This should be used when the client is the Resource owner. Suppose
Expand Down

0 comments on commit cb27984

Please sign in to comment.