Skip to content

Commit

Permalink
Merge pull request #1270 from fecgov/release/sprint-53
Browse files Browse the repository at this point in the history
Release/sprint 53
  • Loading branch information
sasha-dresden authored Jan 15, 2025
2 parents 3cd7947 + eec60c2 commit d36bf1c
Show file tree
Hide file tree
Showing 22 changed files with 852 additions and 122 deletions.
25 changes: 17 additions & 8 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,33 @@ jobs:
working_directory: ~/project/db

- run:
name: Check migrations
name: Check for missing migrations
command: |
python manage.py makemigrations --check
working_directory: ~/project/django-backend/

- run:
name: Check for breaking change migrations
# After December 2024
command: |
python manage.py lintmigrations --git-commit-id d73068e23fc5b035af2b224b16d4726b7b20d67c --project-root-path '.'
working_directory: ~/project/django-backend/

- run:
name: Run migrations
command: |
python manage.py migrate --no-input --traceback --verbosity 3
working_directory: ~/project/django-backend/

- run:
name: Run lint
command: |
flake8 --config django-backend/.flake8
- run:
name: Run deptry
command: deptry ~/project/

- run:
name: Run tests
# Use built-in Django test module
Expand Down Expand Up @@ -113,14 +129,7 @@ jobs:
key: v1-sonarcloud-scanner-5.0.1.3006
paths: /tmp/cache/scanner

- run:
name: Run lint
command: |
flake8 --config django-backend/.flake8

- run:
name: Run deptry
command: deptry ~/project/

deploy-job:
docker:
Expand Down
7 changes: 7 additions & 0 deletions django-backend/.django_migration_linter.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[django_migration_linter]
no_cache = True
verbosity = 3
warnings_as_errors =
RUNPYTHON_REVERSIBLE
RUNSQL_REVERSIBLE
sql_analyser = postgresql
12 changes: 8 additions & 4 deletions django-backend/fecfiler/mock_oidc_provider/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
api_view,
)

from fecfiler.oidc.utils import idp_base64_encode_left_128_bits_of_str
from fecfiler.settings import MOCK_OIDC_PROVIDER_CACHE

from jwcrypto import jwk
Expand Down Expand Up @@ -99,23 +100,26 @@ def authorize(request):
@require_http_methods(["POST"])
def token(request):
auth_data = json.loads(redis_instance.get(MOCK_OIDC_PROVIDER_DATA))
if not auth_data.get("code"):
code = auth_data.get("code")
if not code:
return HttpResponseBadRequest("call to authorize endpoint is required first")
request_code = request.data.get("code")
if request_code != auth_data.get("code"):
if request_code != code:
return HttpResponseBadRequest("authorize code is invalid")

nonce = auth_data.get("nonce")
access_token = auth_data.get("access_token")
token_type = "Bearer"
expires_in = 3600
at_hash = idp_base64_encode_left_128_bits_of_str(access_token)
c_hash = idp_base64_encode_left_128_bits_of_str(code)
args = {
"iss": request.build_absolute_uri().replace(request.path, ""),
"sub": test_username,
"aud": "test_client_id",
"acr": "test_acr",
"at_hash": "test_at_hash",
"c_hash": "test_c_hash",
"at_hash": at_hash,
"c_hash": c_hash,
"exp": time.time() + 60,
"iat": time.time(),
"jti": "test_jti",
Expand Down
31 changes: 22 additions & 9 deletions django-backend/fecfiler/oidc/backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from requests.exceptions import HTTPError

from . import oidc_op_config
from .utils import idp_base64_encode_left_128_bits_of_str

from django.conf import settings

Expand Down Expand Up @@ -96,20 +97,32 @@ def retrieve_matching_jwk(self, kid):
keyset = jwk.JWKSet.from_json(jwks)
return keyset.get_key(kid)

def verify_token(self, token, **kwargs):
"""Validate the token signature."""
nonce = kwargs.get("nonce")

def verify_token(self, id_token, code, access_token, nonce):
jwstoken = jws.JWS()
jwstoken.deserialize(token)
jwstoken.deserialize(id_token)
pub_key = self.retrieve_matching_jwk(jwstoken.jose_header.get("kid"))
jwstoken.verify(pub_key, settings.OIDC_RP_SIGN_ALGO)
self.verify_token_payload(jwstoken.payload, code, access_token, nonce)

payload = json.loads(jwstoken.payload)
token_nonce = payload.get("nonce")
def verify_token_payload(self, id_token_payload, code, access_token, nonce):
access_token_left_128_bits = idp_base64_encode_left_128_bits_of_str(access_token)
code_left_128_bits = idp_base64_encode_left_128_bits_of_str(code)

payload = json.loads(id_token_payload)

token_nonce = payload.get("nonce")
if nonce != token_nonce:
msg = "JWT Nonce verification failed. "
msg = "JWT nonce verification failed."
raise SuspiciousOperation(msg)

token_at_hash = payload.get("at_hash")
if token_at_hash != access_token_left_128_bits:
msg = "JWT at_hash verification failed."
raise SuspiciousOperation(msg)

token_c_hash = payload.get("c_hash")
if token_c_hash != code_left_128_bits:
msg = "JWT c_hash verification failed."
raise SuspiciousOperation(msg)

def get_token(self, payload):
Expand Down Expand Up @@ -201,7 +214,7 @@ def authenticate(self, request, **kwargs):
access_token = token_info.get("access_token")

# Validate the token
self.verify_token(id_token, nonce=nonce)
self.verify_token(id_token, code, access_token, nonce)

return self.get_or_create_user(access_token)

Expand Down
Loading

0 comments on commit d36bf1c

Please sign in to comment.