Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions apps/authorization/tests/test_data_access_grant.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ def setup_test_application_with_user(self, test_user, application_name="an app")
"scope": ["capability-a"],
"expires_in": 86400,
"allow": True,
"state": "0123456789abcdef",
}
response = self.client.post(response["Location"], data=payload)
self.assertEqual(response.status_code, 302)
Expand Down Expand Up @@ -286,6 +287,7 @@ def test_no_action_on_reapproval(self):
"scope": ["capability-a"],
"expires_in": 86400,
"allow": True,
"state": "0123456789abcdef",
}
response = self.client.post(response["Location"], data=payload)

Expand Down Expand Up @@ -401,6 +403,7 @@ def test_permission_deny_on_app_or_org_disabled(self):
"scope": ["capability-a"],
"expires_in": 86400,
"allow": True,
"state": "0123456789abcdef",
}

response = self.client.post(response["Location"], data=payload)
Expand Down
17 changes: 17 additions & 0 deletions apps/dot_ext/tests/test_authorization.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ def test_post_with_valid_non_standard_scheme_granttype_authcode_clienttype_publi
'scope': ['capability-a'],
'expires_in': 86400,
'allow': True,
"state": "0123456789abcdef",
'code_challenge': code_challenge,
'code_challenge_method': 'S256',
}
Expand Down Expand Up @@ -118,6 +119,7 @@ def test_post_with_invalid_non_standard_scheme_granttype_authcode_clienttype_pub
'scope': ['capability-a'],
'expires_in': 86400,
'allow': True,
"state": "0123456789abcdef",
}
response = self.client.post(reverse('oauth2_provider:authorize'), data=payload)
self.assertEqual(response.status_code, 400)
Expand Down Expand Up @@ -159,6 +161,7 @@ def test_post_with_valid_non_standard_scheme_granttype_authcode_clienttype_confi
'scope': ['capability-a'],
'expires_in': 86400,
'allow': True,
"state": "0123456789abcdef",
'code_challenge': code_challenge,
'code_challenge_method': 'S256',
}
Expand Down Expand Up @@ -222,6 +225,7 @@ def test_post_with_invalid_non_standard_scheme_granttype_authcode_clienttype_con
'scope': ['capability-a'],
'expires_in': 86400,
'allow': True,
"state": "0123456789abcdef",
}
response = self.client.post(reverse('oauth2_provider:authorize'), data=payload)
self.assertEqual(response.status_code, 400)
Expand Down Expand Up @@ -250,6 +254,7 @@ def test_refresh_token(self):
'scope': ['capability-a'],
'expires_in': 86400,
'allow': True,
"state": "0123456789abcdef",
}
response = self.client.post(reverse('oauth2_provider:authorize'), data=payload)
self.client.logout()
Expand Down Expand Up @@ -305,6 +310,7 @@ def test_refresh_with_expired_token(self):
'scope': ['capability-a'],
'expires_in': 86400,
'allow': True,
"state": "0123456789abcdef",
}
response = self.client.post(reverse('oauth2_provider:authorize'), data=payload)
self.client.logout()
Expand Down Expand Up @@ -361,6 +367,7 @@ def test_refresh_13_month_with_expired_grant(self):
'scope': ['capability-a'],
'expires_in': 86400,
'allow': True,
"state": "0123456789abcdef",
}
response = self.client.post(reverse('oauth2_provider:authorize'), data=payload)
self.client.logout()
Expand Down Expand Up @@ -425,6 +432,7 @@ def test_refresh_with_one_time_access_retrieve_app_using_refresh_token(self):
'scope': ['capability-a'],
'expires_in': 86400,
'allow': True,
"state": "0123456789abcdef",
}
response = self.client.post(reverse('oauth2_provider:authorize'), data=payload)
self.client.logout()
Expand Down Expand Up @@ -480,6 +488,7 @@ def test_refresh_with_one_time_access_retrieve_app_from_auth_header(self):
'scope': ['capability-a'],
'expires_in': 86400,
'allow': True,
"state": "0123456789abcdef",
}
response = self.client.post(reverse('oauth2_provider:authorize'), data=payload)
self.client.logout()
Expand Down Expand Up @@ -550,6 +559,7 @@ def test_dag_expiration_exists(self):
'scope': ['capability-a'],
'expires_in': 86400,
'allow': True,
"state": "0123456789abcdef",
}
response = self.client.post(reverse('oauth2_provider:authorize'), data=payload)
self.client.logout()
Expand Down Expand Up @@ -594,6 +604,7 @@ def test_revoke_endpoint(self):
'scope': ['capability-a'],
'expires_in': 86400,
'allow': True,
"state": "0123456789abcdef",
}
response = self.client.post(reverse('oauth2_provider:authorize'), data=payload)
self.client.logout()
Expand Down Expand Up @@ -649,6 +660,7 @@ def test_refresh_with_revoked_token(self):
'scope': ['capability-a'],
'expires_in': 86400,
'allow': True,
"state": "0123456789abcdef",
}
response = self.client.post(reverse('oauth2_provider:authorize'), data=payload)
self.client.logout()
Expand Down Expand Up @@ -715,6 +727,7 @@ def test_application_delete_after_auth(self):
'scope': ['capability-a'],
'expires_in': 86400,
'allow': True,
"state": "0123456789abcdef",
}
response = self.client.post(reverse('oauth2_provider:authorize'), data=payload)
self.client.logout()
Expand Down Expand Up @@ -771,6 +784,7 @@ def test_user_delete_after_auth(self):
'scope': ['capability-a'],
'expires_in': 86400,
'allow': True,
"state": "0123456789abcdef",
}
response = self.client.post(reverse('oauth2_provider:authorize'), data=payload)
self.client.logout()
Expand Down Expand Up @@ -831,6 +845,7 @@ def test_revoked_token_on_inactive_app(self):
'scope': ['capability-a'],
'expires_in': 86400,
'allow': True,
"state": "0123456789abcdef",
}
response = self.client.post(reverse('oauth2_provider:authorize'), data=payload)
self.client.logout()
Expand Down Expand Up @@ -900,6 +915,7 @@ def test_introspect_token_on_inactive_app(self):
'scope': ['capability-a', 'capability-b', 'introspection'],
'expires_in': 86400,
'allow': True,
"state": "0123456789abcdef",
}
response = self.client.post(reverse('oauth2_provider:authorize'), data=payload)
self.client.logout()
Expand Down Expand Up @@ -986,6 +1002,7 @@ def _execute_token_endpoint(self, token_path):
'scope': ['capability-a'],
'expires_in': 86400,
'allow': True,
"state": "0123456789abcdef",
}
response = self.client.post(reverse('oauth2_provider:authorize'), data=payload)
self.client.logout()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,9 @@ def test_bene_demo_scopes_change(self):
'response_type': 'code',
'redirect_uri': 'http://example.it',
'expires_in': 86400,
'allow': True}
'allow': True,
"state": "0123456789abcdef",
}

request_scopes = APPLICATION_SCOPES_FULL
# Scopes to be requested in the authorization request
Expand Down
1 change: 1 addition & 0 deletions apps/dot_ext/tests/test_verify_bfd_headers.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ def _create_test_token(self, user, application):
"scope": application.scopes().split(" "),
"expires_in": 86400,
"allow": True,
"state": "0123456789abcdef",
"share_demographic_scopes": True
}
if application.authorization_grant_type == Application.GRANT_IMPLICIT:
Expand Down
3 changes: 3 additions & 0 deletions apps/dot_ext/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ def test_post_with_restricted_scopes_issues_token_with_same_scopes(self):
"scope": ["capability-a"],
"expires_in": 86400,
"allow": True,
"state": "0123456789abcdef",
}
response = self._authorize_and_request_token(payload, application)
self.assertEqual(response.status_code, 200)
Expand Down Expand Up @@ -228,6 +229,7 @@ def test_post_with_share_demographic_scopes(self):
"redirect_uri": "http://example.it",
"expires_in": 86400,
"allow": True,
"state": "0123456789abcdef",
}

# Does the application choose to require demographic info?
Expand Down Expand Up @@ -373,6 +375,7 @@ def _create_test_token(self, user, application):
"scope": application.scopes().split(" "),
"expires_in": 86400,
"allow": True,
"state": "0123456789abcdef",
}
if application.authorization_grant_type == Application.GRANT_IMPLICIT:
payload["response_type"] = "token"
Expand Down
27 changes: 25 additions & 2 deletions apps/dot_ext/views/authorization.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import json
import logging
from datetime import datetime, timedelta
from functools import wraps
from time import strftime

from django.contrib.auth.views import redirect_to_login
from django.http import JsonResponse
from django.http.response import HttpResponse, HttpResponseBadRequest
from django.template.response import TemplateResponse
Expand Down Expand Up @@ -54,6 +56,20 @@ def get_grant_expiration(data_access_type):
pass


def require_post_state_decorator(view_func):
@wraps(view_func)
def _wrapped(request, *args, **kwargs):
if request.method == "POST" and not request.POST.get("state"):
return JsonResponse(
{"status_code": 401, "message": "State required for POST requests."},
status=401,
)
return view_func(request, *args, **kwargs)
return _wrapped


@method_decorator(csrf_exempt, name="dispatch")
@method_decorator(require_post_state_decorator, name="dispatch")
class AuthorizationView(DotAuthorizationView):
"""
Override the base authorization view from dot to
Expand Down Expand Up @@ -117,6 +133,14 @@ def dispatch(self, request, *args, **kwargs):
if lang in ('en', 'es'):
request.session['auth_language'] = lang

if request.method == "POST" and not request.user.is_authenticated:
post_qs = request.POST.urlencode()
# preserve existing query too
existing_qs = request.META.get("QUERY_STRING", "")
merged_qs = f"{existing_qs}&{post_qs}" if existing_qs else post_qs
next_url = f"{request.path}?{merged_qs}"
return redirect_to_login(next_url, login_url=self.login_url)

return super().dispatch(request, *args, **kwargs)

def sensitive_info_check(self, request):
Expand Down Expand Up @@ -292,6 +316,7 @@ def form_valid(self, form):


@method_decorator(csrf_exempt, name="dispatch")
@method_decorator(require_post_state_decorator, name="dispatch")
class ApprovalView(AuthorizationView):
"""
Override the base authorization view from dot to
Expand All @@ -306,8 +331,6 @@ def __init__(self, version=1):
super().__init__()

def dispatch(self, request, uuid, *args, **kwargs):
if request.method == "POST" and request.POST.get("state") is None:
return JsonResponse({"status_code": 401, "message": "State required for POST requests."}, status=401)

# Get auth_uuid to set again after super() return. It gets cleared out otherwise.
auth_flow_dict = get_session_auth_flow_trace(request)
Expand Down
2 changes: 2 additions & 0 deletions apps/logging/tests/test_audit_loggers.py
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,7 @@ def _creation_on_approval_token_logger(self, v2=False):
"scope": ["capability-a"],
"expires_in": 86400,
"allow": True,
"state": "0123456789abcdef",
}
response = self.client.post(response["Location"], data=payload)
self.assertEqual(response.status_code, status.HTTP_302_FOUND)
Expand Down Expand Up @@ -606,6 +607,7 @@ def test_auth_flow_lang_logger(self, v2=False):
"scope": ["capability-a"],
"expires_in": 86400,
"allow": True,
"state": "0123456789abcdef",
}
response = self.client.post(response["Location"], data=payload)
request_log_content = get_log_content(self.logger_registry,
Expand Down
2 changes: 1 addition & 1 deletion apps/mymedicare_cb/tests/test_callback_slsx.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ def test_authorize_uuid(self):
"scope": ["capability-a"],
"expires_in": 86400,
"allow": True,
"state": "1234567890",
"state": "0123456789abcdef",
}
response = self.client.post(auth_uri, data=payload)
self.assertEqual(status.HTTP_302_FOUND, response.status_code)
Expand Down
1 change: 1 addition & 0 deletions apps/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ def _get_access_token_authcode_confidential(
"scope": ["capability-a"],
"expires_in": 86400,
"allow": True,
"state": "0123456789abcdef",
"code_challenge": code_challenge,
"code_challenge_method": "S256",
}
Expand Down
Loading