Skip to content

Commit

Permalink
Merge pull request #269 from rglauco/dev
Browse files Browse the repository at this point in the history
feat: unique jti for each JWT, different RT behaviour between SPID and CIE providers
  • Loading branch information
peppelinux authored Sep 13, 2023
2 parents 49bb356 + 5caa145 commit 68d42e5
Show file tree
Hide file tree
Showing 20 changed files with 346 additions and 92 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ OIDCFED_DEFAULT_TRUST_ANCHOR = "http://127.0.0.1:8000"

OIDCFED_TRUST_ANCHORS = [OIDCFED_DEFAULT_TRUST_ANCHOR]

OIDCFED_PROVIDER_PROFILE = "spid"
OIDCFED_PROVIDER_MAX_REFRESH = 10 #used in SPID
#OIDCFED_PROVIDER_MAX_CONSENT_TIMEFRAME = 3600 #used in CIE (seconds)

# for RP only
OIDCFED_IDENTITY_PROVIDERS = {
"spid": {
Expand Down
6 changes: 4 additions & 2 deletions examples/provider/provider/settingslocal.py.example
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ APPEND_SLASH = False
# required for onboarding checks and also for all the leafs
OIDCFED_DEFAULT_TRUST_ANCHOR = "http://127.0.0.1:8000"
OIDCFED_TRUST_ANCHORS = [OIDCFED_DEFAULT_TRUST_ANCHOR]
OIDCFED_PROVIDER_PROFILE = "cie"

OIDCFED_PROVIDER_PROFILE = "spid"
#OIDCFED_PROVIDER_MAX_REFRESH = 10 #used in SPID
OIDCFED_PROVIDER_MAX_CONSENT_TIMEFRAME = 3600 #used in CIE (seconds)

OIDCFED_REQUIRED_TRUST_MARKS = []

#OIDCFED_FEDERATION_TRUST_MARKS_PROFILES = {
Expand Down
4 changes: 2 additions & 2 deletions spid_cie_oidc/entity/jwtse.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,12 @@ def create_jwe(plain_dict: Union[dict, str, int, None], jwk_dict: dict, **kwargs
if isinstance(plain_dict, dict):
_payload = json.dumps(plain_dict).encode()
elif not plain_dict:
logger.warning(f"create_jwe with null payload!")
logger.warning("create_jwe with null payload!")
_payload = ""
elif isinstance(plain_dict, (str, int)):
_payload = plain_dict
else:
logger.error(f"create_jwe with unsupported payload type!")
logger.error("create_jwe with unsupported payload type!")
_payload = ""

_keyobj = JWE_CLASS(
Expand Down
4 changes: 2 additions & 2 deletions spid_cie_oidc/entity/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@
FEDERATION_DEFAULT_EXP = getattr(settings, "FEDERATION_DEFAULT_EXP", 2880)

ENTITY_TYPE_LEAFS = [
"openid_relying_party",
"openid_provider",
"openid_relying_party",
"openid_provider",
"oauth_resource",
"wallet_provider",
"wallet_relying_party"
Expand Down
2 changes: 1 addition & 1 deletion spid_cie_oidc/entity/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def validate_entity_metadata(value):
raise ValidationError(
f"RP metadata fail {e}. "
)

# TODO - add wallet_provider and wallet_relying_party once standardized


Expand Down
2 changes: 0 additions & 2 deletions spid_cie_oidc/entity/x509.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import datetime
import os

from cryptography import x509
from cryptography.x509.oid import NameOID
Expand Down
2 changes: 1 addition & 1 deletion spid_cie_oidc/onboarding/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ def onboarding_decode_jwt(request):
if not form_dict.get('jwk'):
messages.error(
request,
f"JWE needs a private jwk to be decrypted"
"JWE needs a private jwk to be decrypted"
)
return render(
request, "onboarding_decode_jwt.html", context, status = 400
Expand Down
6 changes: 4 additions & 2 deletions spid_cie_oidc/provider/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@
AuthenticationRequestDoc,
AuthenticationRequestSpid
)
from spid_cie_oidc.provider.schemas.authn_response import AuthenticationErrorResponse, AuthenticationErrorResponseCie, AuthenticationResponse, AuthenticationResponseCie
from spid_cie_oidc.provider.schemas.authn_response import AuthenticationErrorResponse, AuthenticationErrorResponseCie, \
AuthenticationResponse, AuthenticationResponseCie
from spid_cie_oidc.provider.schemas.introspection_request import IntrospectionRequest
from spid_cie_oidc.provider.schemas.introspection_response import IntrospectionErrorResponseCie, IntrospectionErrorResponseSpid, IntrospectionResponse
from spid_cie_oidc.provider.schemas.introspection_response import IntrospectionErrorResponseCie, \
IntrospectionErrorResponseSpid, IntrospectionResponse
from spid_cie_oidc.provider.schemas.revocation_request import RevocationRequest
from spid_cie_oidc.provider.schemas.revocation_response import RevocationErrorResponse
from spid_cie_oidc.provider.schemas.token_requests import TokenAuthnCodeRequest, TokenRefreshRequest
Expand Down
117 changes: 117 additions & 0 deletions spid_cie_oidc/provider/static/svg/spid-logo-c-lb.svg-LTS.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
78 changes: 74 additions & 4 deletions spid_cie_oidc/provider/tests/test_03_refresh_token.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from copy import deepcopy

import time
from cryptojwt.jws.utils import left_hash
from django.test import Client, TestCase, override_settings
from django.urls import reverse
from django.utils import timezone
Expand Down Expand Up @@ -66,6 +67,31 @@ def setUp(self):
"scope": "openid",
}
self.rt_jws = create_jws(refresh_token, op_conf_priv_jwk)
id_token = {
'sub': '2ed008b45e66ce53e48273dca5a4463bc8ebd036ebaa824f4582627683c2451b',
'nonce': 'ljbvL3rpscgS4ZGda7cgibXHr7vrNREW',
'at_hash': '',
'c_hash': 'tij0h-zL_bSrsVXy-d3qHw',
'aud': [rp_conf["metadata"]["openid_relying_party"]["client_id"], ],
'iss': op_conf["sub"],
'jti': '402e61bd-950c-4934-83d4-c09a05468828',
'exp': exp_from_now(),
'iat': iat_now()
}
access_token = {
'iss': op_conf["sub"],
'sub': '2ed008b45e66ce53e48273dca5a4463bc8ebd036ebaa824f4582627683c2451b',
'aud': [rp_conf["metadata"]["openid_relying_party"]["client_id"], ],
'client_id': rp_conf["metadata"]["openid_relying_party"]["client_id"],
'scope': 'openid',
'jti': '402e61bd-950c-4934-83d4-c09a05468828',
'exp': exp_from_now(),
'iat': iat_now()
}
self.jwt_at = create_jws(access_token, op_conf_priv_jwk, typ="at+jwt")
id_token['at_hash'] = left_hash(self.jwt_at, "HS256")
self.jwt_id = create_jws(id_token, op_conf_priv_jwk)

session = OidcSession.objects.create(
user=User.objects.create(username="username"),
user_uid="",
Expand All @@ -77,11 +103,15 @@ def setUp(self):
)
IssuedToken.objects.create(
refresh_token=self.rt_jws,
id_token=self.jwt_id,
access_token=self.jwt_at,
session=session,
expires=timezone.localtime()
)
self.assertEqual(refresh_token["iss"], self.op_local_conf["sub"])

def test_grant_refresh_token(self):
@override_settings(OIDCFED_PROVIDER_PROFILE="spid")
def test_grant_refresh_token_spid(self):
client = Client()
url = reverse("oidc_provider_token_endpoint")
request = dict(
Expand All @@ -97,8 +127,47 @@ def test_grant_refresh_token(self):
self.assertEqual(refresh_token["aud"], RP_CLIENT_ID)
self.assertEqual(refresh_token["iss"], self.op_local_conf["sub"])

@override_settings(OIDCFED_PROVIDER_MAX_REFRESH=1)
def test_grant_refresh_token_two_times(self):
@override_settings(OIDCFED_PROVIDER_PROFILE="cie")
def test_grant_refresh_token_cie(self):
client = Client()
url = reverse("oidc_provider_token_endpoint")
request = dict(
client_id=RP_CLIENT_ID,
client_assertion=self.ca_jws,
client_assertion_type="urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
refresh_token=self.rt_jws,
grant_type="refresh_token"
)
res = client.post(url, request)
self.assertTrue(res.status_code == 200)
refresh_token = verify_jws(res.json().get("refresh_token"), op_conf_priv_jwk)
self.assertEqual(refresh_token["aud"], RP_CLIENT_ID)

@override_settings(OIDCFED_PROVIDER_MAX_REFRESH=1, OIDCFED_PROVIDER_PROFILE="spid")
def test_grant_refresh_token_two_times_spid(self):
client = Client()
url = reverse("oidc_provider_token_endpoint")
request = dict(
client_id=RP_CLIENT_ID,
client_assertion=self.ca_jws,
client_assertion_type="urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
refresh_token=self.rt_jws,
grant_type="refresh_token"
)
res = client.post(url, request)
self.assertTrue(res.status_code == 200)
request = dict(
client_id=RP_CLIENT_ID,
client_assertion=self.ca_jws,
client_assertion_type="urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
refresh_token=res.json()["refresh_token"],
grant_type="refresh_token"
)
res = client.post(url, request)
self.assertTrue(res.status_code == 400)

@override_settings(OIDCFED_PROVIDER_MAX_CONSENT_TIMEFRAME=1, OIDCFED_PROVIDER_PROFILE="cie")
def test_grant_refresh_token_two_times_cie(self):
client = Client()
url = reverse("oidc_provider_token_endpoint")
request = dict(
Expand All @@ -117,5 +186,6 @@ def test_grant_refresh_token_two_times(self):
refresh_token=res.json()["refresh_token"],
grant_type="refresh_token"
)
time.sleep(2)
res = client.post(url, request)
self.assertTrue(res.status_code == 400)
6 changes: 4 additions & 2 deletions spid_cie_oidc/provider/views/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,6 @@ def validate_json_schema(self, payload, schema_type, error_description):

def get_jwt_common_data(self):
return {
"jti": str(uuid.uuid4()),
"exp": exp_from_now(),
"iat": iat_now()
}
Expand All @@ -253,6 +252,7 @@ def get_access_token(
"aud": [authz.client_id],
"client_id": authz.client_id,
"scope": authz.authz_request["scope"],
"jti": str(uuid.uuid4())
}
access_token.update(commons)

Expand Down Expand Up @@ -293,7 +293,8 @@ def get_id_token(
"c_hash": left_hash(authz.auth_code, "HS256"),
"aud": [authz.client_id],
"iss": iss_sub,
"acr": authz.acr
"acr": authz.acr,
"jti": str(uuid.uuid4())
}
claims = self.get_id_token_claims(authz)
if claims:
Expand Down Expand Up @@ -324,6 +325,7 @@ def get_refresh_token(
"c_hash": left_hash(authz.auth_code, "HS256"),
"aud": authz.client_id,
"iss": iss_sub,
"jti": str(uuid.uuid4())
}
refresh_token.update(commons)
return refresh_token
Expand Down
Loading

0 comments on commit 68d42e5

Please sign in to comment.