Skip to content

Commit

Permalink
feat: Allow trusted apps to perform cookie login.
Browse files Browse the repository at this point in the history
  • Loading branch information
Kelketek authored and xitij2000 committed Oct 25, 2024
1 parent ab6d8cb commit fb28a8d
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 7 deletions.
12 changes: 10 additions & 2 deletions openedx/core/djangoapps/auth_exchange/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,11 +168,15 @@ def _verify_response(self, access_token, expected_status_code, token_type='Beare
if expected_cookie_name:
assert expected_cookie_name in response.cookies

def _create_dot_access_token(self, grant_type='Client credentials'):
def _create_dot_access_token(self, grant_type='Client credentials', skip_authorization=False):
"""
Create dot based access token
"""
dot_application = dot_factories.ApplicationFactory(user=self.user, authorization_grant_type=grant_type)
dot_application = dot_factories.ApplicationFactory(
user=self.user,
authorization_grant_type=grant_type,
skip_authorization=skip_authorization,
)
return dot_factories.AccessTokenFactory(user=self.user, application=dot_application)

def test_failure_with_invalid_token(self):
Expand All @@ -189,6 +193,10 @@ def test_failure_with_dot_client_credentials_unsupported(self):
access_token = self._create_dot_access_token()
self._verify_response(access_token, expected_status_code=401)

def test_dot_client_credentials_supported_if_authorization_skipped(self):
access_token = self._create_dot_access_token(skip_authorization=True)
self._verify_response(access_token, expected_status_code=204, expected_cookie_name='sessionid')

def _create_jwt_token(self, grant_type='password', scope='email profile', use_asymmetric_key=True):
"""
Create jwt token
Expand Down
16 changes: 11 additions & 5 deletions openedx/core/djangoapps/auth_exchange/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,10 @@ def _get_path_of_arbitrary_backend_for_user(user):
return backend_path

@staticmethod
def _ensure_access_token_has_password_grant(request):
def _ensure_access_token_has_password_grant_or_privileged_application(request):
"""
Ensures the access token provided has password type grant.
Ensures the access token provided has password type grant, or if 'skip_authorization'
has been enabled, implying this is a trusted application.
"""
if is_jwt_authenticated(request):
jwt_payload = get_decoded_jwt_from_auth(request)
Expand All @@ -143,12 +144,17 @@ def _ensure_access_token_has_password_grant(request):
else:
token_query = dot_models.AccessToken.objects.select_related('user')
dot_token = token_query.filter(token=request.auth).first()
if dot_token and dot_token.application.authorization_grant_type == dot_models.Application.GRANT_PASSWORD:
if dot_token and (
dot_token.application.authorization_grant_type == dot_models.Application.GRANT_PASSWORD
or dot_token.application.skip_authorization
):
return

raise AuthenticationFailed({
'error_code': 'non_supported_token',
'developer_message': 'Only access tokens with grant type password are supported.'
'developer_message': 'Only Django Oauth Toolkit access tokens for applications which '
'are trusted (with "skip_authentication" set to True, or with grant type '
'password) are supported.'
})

@staticmethod
Expand Down Expand Up @@ -194,7 +200,7 @@ def post(self, request):
request.user.backend = self._get_path_of_arbitrary_backend_for_user(request.user)

self._ensure_user_is_not_disabled(request)
self._ensure_access_token_has_password_grant(request)
self._ensure_access_token_has_password_grant_or_privileged_application(request)
self._ensure_jwt_is_asymmetric(request)

login(request, request.user) # login generates and stores the user's cookies in the session
Expand Down

0 comments on commit fb28a8d

Please sign in to comment.