feat: link local library
This commit is contained in:
+165
@@ -0,0 +1,165 @@
|
||||
from django.test import Client
|
||||
from django.urls import reverse
|
||||
|
||||
from spid_cie_oidc.authority.models import FederationDescendant
|
||||
from spid_cie_oidc.entity.models import FederationEntityConfiguration
|
||||
from spid_cie_oidc.entity.jwtse import unpad_jwt_payload, create_jws
|
||||
from spid_cie_oidc.entity.exceptions import HttpError
|
||||
from spid_cie_oidc.entity.tests.settings import ta_conf_data
|
||||
|
||||
from .settings import rp_onboarding_data, intermediary_conf, rp_conf
|
||||
|
||||
import copy
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DummyContent:
|
||||
def __init__(self, content):
|
||||
self.content = content.encode()
|
||||
self.status_code = 200
|
||||
|
||||
|
||||
class EntityResponse:
|
||||
def __init__(self):
|
||||
self.status_code = 200
|
||||
self.req_counter = 0
|
||||
self.client = Client()
|
||||
self.result = None
|
||||
|
||||
def result_as_it_is(self):
|
||||
logger.info(f"Response #{self.req_counter}: {self.result.content.decode()}")
|
||||
self.req_counter += 1
|
||||
return self.result.content
|
||||
|
||||
def result_as_jws(self):
|
||||
logger.info(
|
||||
f"Response #{self.req_counter}: "
|
||||
f"{unpad_jwt_payload(self.result.content.decode())}"
|
||||
)
|
||||
self.req_counter += 1
|
||||
return self.result.content
|
||||
|
||||
def trust_anchor_ec(self):
|
||||
url = reverse("entity_configuration")
|
||||
res = self.client.get(url, data={"sub": ta_conf_data["sub"]})
|
||||
return res
|
||||
|
||||
def rp_ec(self):
|
||||
rp = FederationEntityConfiguration.objects.get(sub=rp_onboarding_data["sub"])
|
||||
res = DummyContent(rp.entity_configuration_as_jws)
|
||||
return res
|
||||
|
||||
def fetch_rp_from_ta(self):
|
||||
url = reverse("oidcfed_fetch")
|
||||
res = self.client.get(url, data={"sub": rp_onboarding_data["sub"]})
|
||||
return res
|
||||
|
||||
|
||||
class EntityResponseNoIntermediate(EntityResponse):
|
||||
@property
|
||||
def content(self):
|
||||
if self.req_counter == 0:
|
||||
self.result = self.trust_anchor_ec()
|
||||
elif self.req_counter == 1:
|
||||
self.result = self.rp_ec()
|
||||
elif self.req_counter == 2:
|
||||
self.result = self.fetch_rp_from_ta()
|
||||
elif self.req_counter > 2:
|
||||
raise NotImplementedError(
|
||||
"The mocked resposes seems to be not aligned with the correct flow"
|
||||
)
|
||||
|
||||
return self.result_as_jws()
|
||||
|
||||
class EntityResponseNoIntermediateSignedJwksUri(EntityResponse):
|
||||
@property
|
||||
def content(self):
|
||||
if self.req_counter == 0:
|
||||
self.result = self.trust_anchor_ec()
|
||||
elif self.req_counter == 1:
|
||||
self.result = self.rp_ec()
|
||||
elif self.req_counter == 2:
|
||||
self.result = self.fetch_rp_from_ta()
|
||||
elif self.req_counter == 3:
|
||||
metadata = copy.deepcopy(rp_conf['metadata']['openid_relying_party'])
|
||||
_jwks = metadata.pop('jwks')
|
||||
fed_jwks = rp_conf['jwks_fed'][0]
|
||||
self.result = create_jws(_jwks, fed_jwks)
|
||||
return self.result.encode()
|
||||
elif self.req_counter > 3:
|
||||
raise NotImplementedError(
|
||||
"The mocked resposes seems to be not aligned with the correct flow"
|
||||
)
|
||||
|
||||
return self.result_as_jws()
|
||||
|
||||
|
||||
class EntityResponseWithIntermediate(EntityResponse):
|
||||
@property
|
||||
def content(self):
|
||||
if self.req_counter == 0:
|
||||
self.result = self.trust_anchor_ec()
|
||||
elif self.req_counter == 1:
|
||||
self.result = self.rp_ec()
|
||||
elif self.req_counter == 2:
|
||||
sa = FederationEntityConfiguration.objects.get(sub=intermediary_conf["sub"])
|
||||
self.result = DummyContent(sa.entity_configuration_as_jws)
|
||||
elif self.req_counter == 3:
|
||||
# Subordinate statement: intermediate -> RP (not TA -> RP)
|
||||
rp_desc = FederationDescendant.objects.get(sub=rp_onboarding_data["sub"])
|
||||
stmt_jws = rp_desc.entity_statement_as_jws(intermediary_conf["sub"])
|
||||
self.result = DummyContent(stmt_jws)
|
||||
elif self.req_counter == 4:
|
||||
url = reverse("oidcfed_fetch")
|
||||
self.result = self.client.get(url, data={"sub": intermediary_conf["sub"]})
|
||||
elif self.req_counter == 5:
|
||||
url = reverse("entity_configuration")
|
||||
self.result = self.client.get(url, data={"sub": ta_conf_data["sub"]})
|
||||
elif self.req_counter > 5:
|
||||
raise NotImplementedError(
|
||||
"The mocked resposes seems to be not aligned with the correct flow"
|
||||
)
|
||||
|
||||
if self.result.status_code != 200:
|
||||
raise HttpError(f"Something went wrong with Http Request: {self.result.__dict__}")
|
||||
|
||||
logger.info("-------------------------------------------------")
|
||||
logger.info("")
|
||||
return self.result_as_jws()
|
||||
|
||||
|
||||
class EntityResponseWithIntermediateManyHints(EntityResponse):
|
||||
@property
|
||||
def content(self):
|
||||
if self.req_counter == 0:
|
||||
self.result = self.trust_anchor_ec()
|
||||
elif self.req_counter == 1:
|
||||
self.result = self.rp_ec()
|
||||
elif self.req_counter == 2:
|
||||
sa = FederationEntityConfiguration.objects.get(sub=intermediary_conf["sub"])
|
||||
self.result = DummyContent(sa.entity_configuration_as_jws)
|
||||
elif self.req_counter == 3:
|
||||
# Second authority hint (that-faulty): invalid response
|
||||
self.result = DummyContent("crap")
|
||||
elif self.req_counter == 4:
|
||||
# Subordinate statement: intermediate -> RP
|
||||
rp_desc = FederationDescendant.objects.get(sub=rp_onboarding_data["sub"])
|
||||
stmt_jws = rp_desc.entity_statement_as_jws(intermediary_conf["sub"])
|
||||
self.result = DummyContent(stmt_jws)
|
||||
elif self.req_counter == 5:
|
||||
# TA -> intermediate subordinate statement
|
||||
url = reverse("oidcfed_fetch")
|
||||
self.result = self.client.get(url, data={"sub": intermediary_conf["sub"]})
|
||||
elif self.req_counter > 5:
|
||||
raise NotImplementedError(
|
||||
"The mocked resposes seems to be not aligned with the correct flow"
|
||||
)
|
||||
if self.result.status_code != 200:
|
||||
raise HttpError(f"Something went wrong with Http Request: {self.result.__dict__}")
|
||||
|
||||
try:
|
||||
return self.result_as_jws()
|
||||
except:
|
||||
return self.result_as_it_is()
|
||||
@@ -0,0 +1,149 @@
|
||||
from copy import deepcopy
|
||||
from spid_cie_oidc.entity.jwks import serialize_key, new_rsa_key
|
||||
|
||||
INTERMEDIARY_RSA = new_rsa_key()
|
||||
INTERMEDIARY_JWK1 = serialize_key(INTERMEDIARY_RSA.priv_key, kind='private')
|
||||
INTERMEDIARY_JWK1_pub = serialize_key(INTERMEDIARY_RSA.pub_key)
|
||||
|
||||
RP_METADATA_JWK1 = {'use': 'sig', 'kty': 'RSA', 'n': 'w8H80eT2zrs2XQ-SApZG9TkuXDuIxANfCVHt4fFqNnOEZaCNWqlTQIo0JiSBE-QmzZ09TYP1BJpESuQf_PUeLRVPfYHsBVk5OYvhT27_nYlV7_1LsFGLxxsIa-hswMMzvW-1_huKLy6Fp0WP0ouUJAHsF_eYVtO1ApRhvlIVd5azM4k7t8Lh8lkCSdF1SfGHfXnXJRb-XensZ0cFSfe2Koq9mD7jpGLXlPpXxj8Ow0g7KYT5kVtWE5ULmNmO7BIN1Hx4HpggbbEGgC9FyjKw4GfFb-csnB-icBPf_60HomjrkFFt6vTjrcqQaHOj-sEjP36N8rMSBiMmiMSPnsHhMQ', 'e': 'AQAB', 'd': 'jEDxjcTZXBbgBV8Bgt7-qfW1FJoHDEFKFxhfMpHQQoETa-jTPhCxOD2MzYM8A-9kKc8tu9r-crTAl1PI42kPnMd283phixd5G5Tv8gSaGdnq-45ka0iRuC7TItUdDiMNb_2YzB4ZLGLNmaIKQJSGqCHEcQuRVyxJtTZwrXaMMOhDqJaWUvUQWF5C7g5O5mOVTkNKw6ujzhqcWa4N3NE-HwcbVW_9st4s1c_ng-DlwLTptaeM5j-LOeZMX1zcVlwYMi5ZkYYY6FHHjYI4nBWDtqhvf-64QaTv8exIjk8PcxHOwhfLTWiHPLk14af7U_pCzkP87WQCBgNfvt3WILQ5DQ', 'p': '75eNHkWaYQMgzVfFwif5uftSxqOhFU6VkxNKdqoRuFxJuVTO-M-vbQc3BwPxms2xrpizU6zGcoPGPvccDi0G040wZh34pWDVABMgGMKXKmeTwj8FuM1DzOVq8DKHmdrhk1gaQbPAP8JVOVYK7uh_lG5wmz3X-En1McMk-E8g8Ic', 'q': '0Sny6DLNtDP1_B9qiyCaMtRqPSAUZ1ohCZRlBT6-IGRR31Kt5S2JcVNDnF5w4dunlDY4nhIBZ0v0VyzWKgDXj6qrFY1pm1iE29gW227YsVRWQU8xWGpBwEu8nxNMr0u0zfe0QEGWU4RvNAsZPRa31HU87Vm7I3NSZ34DZsCZJoc', 'kid': 'HIvo33-Km7n03ZqKDJfWVnlFudsW28YhQZx5eaXtAKA'}
|
||||
RP_METADATA_JWK1_pub = {'use': 'sig', 'kty': 'RSA', 'n': 'w8H80eT2zrs2XQ-SApZG9TkuXDuIxANfCVHt4fFqNnOEZaCNWqlTQIo0JiSBE-QmzZ09TYP1BJpESuQf_PUeLRVPfYHsBVk5OYvhT27_nYlV7_1LsFGLxxsIa-hswMMzvW-1_huKLy6Fp0WP0ouUJAHsF_eYVtO1ApRhvlIVd5azM4k7t8Lh8lkCSdF1SfGHfXnXJRb-XensZ0cFSfe2Koq9mD7jpGLXlPpXxj8Ow0g7KYT5kVtWE5ULmNmO7BIN1Hx4HpggbbEGgC9FyjKw4GfFb-csnB-icBPf_60HomjrkFFt6vTjrcqQaHOj-sEjP36N8rMSBiMmiMSPnsHhMQ', 'e': 'AQAB', 'kid': 'HIvo33-Km7n03ZqKDJfWVnlFudsW28YhQZx5eaXtAKA'}
|
||||
|
||||
RP_METADATA_JWK2 = {'alg': 'RSA-OAEP', 'use': 'enc', 'kty': 'RSA', 'n': 'w8H80eT2zrs2XQ-SApZG9TkuXDuIxANfCVHt4fFqNnOEZaCNWqlTQIo0JiSBE-QmzZ09TYP1BJpESuQf_PUeLRVPfYHsBVk5OYvhT27_nYlV7_1LsFGLxxsIa-hswMMzvW-1_huKLy6Fp0WP0ouUJAHsF_eYVtO1ApRhvlIVd5azM4k7t8Lh8lkCSdF1SfGHfXnXJRb-XensZ0cFSfe2Koq9mD7jpGLXlPpXxj8Ow0g7KYT5kVtWE5ULmNmO7BIN1Hx4HpggbbEGgC9FyjKw4GfFb-csnB-icBPf_60HomjrkFFt6vTjrcqQaHOj-sEjP36N8rMSBiMmiMSPnsHhMQ', 'e': 'AQAB', 'd': 'jEDxjcTZXBbgBV8Bgt7-qfW1FJoHDEFKFxhfMpHQQoETa-jTPhCxOD2MzYM8A-9kKc8tu9r-crTAl1PI42kPnMd283phixd5G5Tv8gSaGdnq-45ka0iRuC7TItUdDiMNb_2YzB4ZLGLNmaIKQJSGqCHEcQuRVyxJtTZwrXaMMOhDqJaWUvUQWF5C7g5O5mOVTkNKw6ujzhqcWa4N3NE-HwcbVW_9st4s1c_ng-DlwLTptaeM5j-LOeZMX1zcVlwYMi5ZkYYY6FHHjYI4nBWDtqhvf-64QaTv8exIjk8PcxHOwhfLTWiHPLk14af7U_pCzkP87WQCBgNfvt3WILQ5DQ', 'p': '75eNHkWaYQMgzVfFwif5uftSxqOhFU6VkxNKdqoRuFxJuVTO-M-vbQc3BwPxms2xrpizU6zGcoPGPvccDi0G040wZh34pWDVABMgGMKXKmeTwj8FuM1DzOVq8DKHmdrhk1gaQbPAP8JVOVYK7uh_lG5wmz3X-En1McMk-E8g8Ic', 'q': '0Sny6DLNtDP1_B9qiyCaMtRqPSAUZ1ohCZRlBT6-IGRR31Kt5S2JcVNDnF5w4dunlDY4nhIBZ0v0VyzWKgDXj6qrFY1pm1iE29gW227YsVRWQU8xWGpBwEu8nxNMr0u0zfe0QEGWU4RvNAsZPRa31HU87Vm7I3NSZ34DZsCZJoc', 'kid': 'ENC-Km7n03ZqKDJfWVnlFudsW28YhQZx5eaXtAKA'}
|
||||
RP_METADATA_JWK2_pub = {'alg': 'RSA-OAEP', 'use': 'enc', 'kty': 'RSA', 'n': 'w8H80eT2zrs2XQ-SApZG9TkuXDuIxANfCVHt4fFqNnOEZaCNWqlTQIo0JiSBE-QmzZ09TYP1BJpESuQf_PUeLRVPfYHsBVk5OYvhT27_nYlV7_1LsFGLxxsIa-hswMMzvW-1_huKLy6Fp0WP0ouUJAHsF_eYVtO1ApRhvlIVd5azM4k7t8Lh8lkCSdF1SfGHfXnXJRb-XensZ0cFSfe2Koq9mD7jpGLXlPpXxj8Ow0g7KYT5kVtWE5ULmNmO7BIN1Hx4HpggbbEGgC9FyjKw4GfFb-csnB-icBPf_60HomjrkFFt6vTjrcqQaHOj-sEjP36N8rMSBiMmiMSPnsHhMQ', 'e': 'AQAB', 'kid': 'ENC-Km7n03ZqKDJfWVnlFudsW28YhQZx5eaXtAKA'}
|
||||
|
||||
rp_onboarding_data = dict(
|
||||
name="RP Test",
|
||||
sub="http://rp-test.it/oidc/rp/",
|
||||
type="openid_relying_party",
|
||||
metadata_policy={"openid_relying_party": {"scope": {"value": ["openid"]}}},
|
||||
is_active=True,
|
||||
jwks = [RP_METADATA_JWK1_pub]
|
||||
)
|
||||
|
||||
rp_conf = {
|
||||
"sub": rp_onboarding_data["sub"],
|
||||
"jwks_fed" : [RP_METADATA_JWK1],
|
||||
"jwks_core" : [RP_METADATA_JWK1, RP_METADATA_JWK2],
|
||||
"metadata": {
|
||||
"openid_relying_party": {
|
||||
"application_type": "web",
|
||||
"client_registration_types": ["automatic"],
|
||||
"client_name": "Name of this service called http://rp-test.it/oidc/rp/",
|
||||
"contacts": ["[email protected]"],
|
||||
"grant_types": ["refresh_token", "authorization_code"],
|
||||
"redirect_uris": ["http://rp-test.it/oidc/rp/callback/"],
|
||||
"response_types": ["code"],
|
||||
"subject_type": "pairwise",
|
||||
"client_id": "http://rp-test.it/oidc/rp/",
|
||||
"jwks": {"keys": [RP_METADATA_JWK1_pub, RP_METADATA_JWK2_pub]},
|
||||
}
|
||||
},
|
||||
"authority_hints": ["http://testserver/"],
|
||||
"is_active": True,
|
||||
}
|
||||
|
||||
RP_CONF_AS_JSON = {
|
||||
"iss": rp_conf["sub"],
|
||||
"sub": rp_conf["sub"],
|
||||
"jwks": {
|
||||
"keys": [RP_METADATA_JWK1_pub, RP_METADATA_JWK2_pub]
|
||||
},
|
||||
"metadata": rp_conf["metadata"],
|
||||
"authority_hints":rp_conf["authority_hints"]
|
||||
}
|
||||
|
||||
intermediary_conf = {
|
||||
"sub": "http://intermediary-test",
|
||||
"metadata": {
|
||||
"federation_entity": {
|
||||
"contacts": ["ops@localhost"],
|
||||
"federation_fetch_endpoint": "http://intermediary-test/fetch",
|
||||
"homepage_uri": "http://intermediary-test",
|
||||
"name": "example Intermediate",
|
||||
}
|
||||
},
|
||||
"trust_marks": [],
|
||||
"authority_hints": ["http://testserver/"],
|
||||
"is_active": True,
|
||||
"jwks_core": [INTERMEDIARY_JWK1],
|
||||
"jwks_fed": [INTERMEDIARY_JWK1]
|
||||
}
|
||||
intermediary_onboarding_data = dict(
|
||||
name="intermediary-test",
|
||||
sub="http://intermediary-test",
|
||||
type="federation_entity",
|
||||
# metadata_policy = {"openid_relying_party": {"scope": {"value": ["openid"]}}},
|
||||
is_active=True,
|
||||
jwks = [INTERMEDIARY_JWK1_pub]
|
||||
)
|
||||
|
||||
|
||||
TRUST_MARK_PAYLOAD = {
|
||||
"iss": "$.issuer_sub",
|
||||
"sub": "$.sub",
|
||||
"iat": 1579621160,
|
||||
"trust_mark_id": "https://www.spid.gov.it/certification/rp",
|
||||
"logo_uri": "https://www.agid.gov.it/themes/custom/agid/logo.svg",
|
||||
"ref": "https://docs.italia.it/italia/spid/spid-regole-tecniche-oidc/it/stabile/index.html",
|
||||
}
|
||||
|
||||
RP_PROFILE = {
|
||||
"name": "SPID Public SP",
|
||||
"profile_category": "openid_relying_party",
|
||||
"profile_id": "https://www.spid.gov.it/certification/rp",
|
||||
"trust_mark_template": TRUST_MARK_PAYLOAD,
|
||||
}
|
||||
|
||||
RP_METADATA = {
|
||||
"openid_relying_party": {
|
||||
"application_type": "web",
|
||||
"client_registration_types": ["automatic"],
|
||||
"client_name": f"Name of this service called {rp_onboarding_data['sub']}",
|
||||
"contacts": ["[email protected]"],
|
||||
"grant_types": ["refresh_token", "authorization_code"],
|
||||
"jwks": {"keys": [RP_METADATA_JWK1_pub]},
|
||||
"redirect_uris": [f"{rp_onboarding_data['sub']}/callback/"],
|
||||
"response_types": ["code"],
|
||||
"subject_type": "pairwise",
|
||||
}
|
||||
}
|
||||
|
||||
TA_SUB = "http://testserver.it/"
|
||||
|
||||
FETCH_REQUEST = {
|
||||
"sub": rp_conf["sub"],
|
||||
}
|
||||
|
||||
LIST_REQUEST = {
|
||||
"entity_type": "openid_relying_party",
|
||||
}
|
||||
|
||||
TRUST_MARK = "eyJhbGciOiJSUzI1NiIsImtpZCI6IkZpZll4MDNibm9zRDhtNmdZUUlmTkhOUDljTV9TYW05VGM1bkxsb0lJcmMiLCJ0eXAiOiJ0cnVzdC1tYXJrK2p3dCJ9.eyJpc3MiOiJodHRwOi8vMTI3LjAuMC4xOjgwMDAvIiwic3ViIjoiaHR0cDovLzEyNy4wLjAuMTo4MDAyL29pZGMvb3AvIiwiaWF0IjoxNjQ4NTcxMTk4LCJpZCI6Imh0dHBzOi8vd3d3LnNwaWQuZ292Lml0L2NlcnRpZmljYXRpb24vb3AiLCJtYXJrIjoiaHR0cHM6Ly93d3cuYWdpZC5nb3YuaXQvdGhlbWVzL2N1c3RvbS9hZ2lkL2xvZ28uc3ZnIiwicmVmIjoiaHR0cHM6Ly9kb2NzLml0YWxpYS5pdC9pdGFsaWEvc3BpZC9zcGlkLXJlZ29sZS10ZWNuaWNoZS1vaWRjL2l0L3N0YWJpbGUvaW5kZXguaHRtbCJ9.mN-AMOmcxOKh9w8SIw9T0N4_wsmjrnMsPp_M2k3irErz0ikrRNtOQ0iPXhJ33szXUxZQJc0jlxu3glCliViv34u6FyAUK-WyVHWf2QKHL5oPbZj45Lx6u1ZMTgU9gKEAUl6MdkGtIEU6F0-q87-BKIKTvJmErH3pdrQG7ed5fR2lvFCN7QQ4rHnVYHVMEnlZxe2oMPtRILsSHaa30yPGCYfp36BpZx9rdmrV0bb8sIsRYFin7GIhkzl4FxqEQ0J6i1A4elgP9tVQsOu1Yd4E54t62KdVtTgfI4qfmP15NoPiNZFHLIFIMsUmqHMh5nuq9KWBb2IC1dfHM6AoxCpqtQ"
|
||||
|
||||
TRUST_MARK_REQUEST = {
|
||||
"sub": rp_conf["sub"],
|
||||
"trust_mark_id" : rp_conf["sub"],
|
||||
"trust_mark" : TRUST_MARK
|
||||
}
|
||||
|
||||
TRUST_MARK_REQUEST_NO_SUB_ID = deepcopy(TRUST_MARK_REQUEST)
|
||||
TRUST_MARK_REQUEST_NO_SUB_ID.pop("sub")
|
||||
TRUST_MARK_REQUEST_NO_SUB_ID.pop("trust_mark_id")
|
||||
|
||||
TRUST_MARK_REQUEST_NO_TRUST_MARK = deepcopy(TRUST_MARK_REQUEST)
|
||||
TRUST_MARK_REQUEST_NO_TRUST_MARK.pop("trust_mark")
|
||||
|
||||
TRUST_MARK_REQUEST_TRUST_MARK_NO_SUB = deepcopy(TRUST_MARK_REQUEST)
|
||||
TRUST_MARK_REQUEST_TRUST_MARK_NO_SUB.pop("sub")
|
||||
|
||||
TRUST_MARK_REQUEST_TRUST_MARK_NO_SUB_NO_TRUST_MARK = deepcopy(TRUST_MARK_REQUEST)
|
||||
TRUST_MARK_REQUEST_TRUST_MARK_NO_SUB_NO_TRUST_MARK.pop("sub")
|
||||
TRUST_MARK_REQUEST_TRUST_MARK_NO_SUB_NO_TRUST_MARK.pop("trust_mark")
|
||||
|
||||
TRUST_MARK_REQUEST_TRUST_MARK_NO_ID_NO_TRUST_MARK = deepcopy(TRUST_MARK_REQUEST)
|
||||
TRUST_MARK_REQUEST_TRUST_MARK_NO_ID_NO_TRUST_MARK.pop("trust_mark_id")
|
||||
TRUST_MARK_REQUEST_TRUST_MARK_NO_ID_NO_TRUST_MARK.pop("trust_mark")
|
||||
|
||||
ADVANCED_LIST_REQUEST = {
|
||||
"page": 1,
|
||||
}
|
||||
Vendored
+385
@@ -0,0 +1,385 @@
|
||||
from django.test import TestCase, Client, override_settings
|
||||
from django.urls import reverse
|
||||
|
||||
from spid_cie_oidc.entity.exceptions import InvalidRequiredTrustMark
|
||||
from spid_cie_oidc.entity.jwtse import verify_jws, unpad_jwt_head, unpad_jwt_payload
|
||||
from spid_cie_oidc.entity.models import *
|
||||
|
||||
from spid_cie_oidc.entity.trust_chain_operations import (
|
||||
dumps_statements_from_trust_chain_to_db,
|
||||
get_or_create_trust_chain,
|
||||
trust_chain_builder,
|
||||
)
|
||||
from spid_cie_oidc.entity.statements import (
|
||||
EntityConfiguration,
|
||||
get_entity_configurations,
|
||||
TrustMark,
|
||||
)
|
||||
from spid_cie_oidc.entity.utils import get_jwks
|
||||
from spid_cie_oidc.entity.tests.settings import *
|
||||
|
||||
from spid_cie_oidc.authority.models import *
|
||||
from spid_cie_oidc.authority.tests.mocked_responses import *
|
||||
from spid_cie_oidc.authority.tests.settings import *
|
||||
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
import copy
|
||||
import datetime
|
||||
|
||||
|
||||
class TrustChainTest(TestCase):
|
||||
def setUp(self):
|
||||
self.ta_conf = FederationEntityConfiguration.objects.create(**ta_conf_data)
|
||||
self.rp_conf = FederationEntityConfiguration.objects.create(**rp_conf)
|
||||
|
||||
self.rp_profile = FederationEntityProfile.objects.create(**RP_PROFILE)
|
||||
self.rp = FederationDescendant.objects.create(**rp_onboarding_data)
|
||||
|
||||
self.rp_assigned_profile = FederationEntityAssignedProfile.objects.create(
|
||||
descendant=self.rp, profile=self.rp_profile, issuer=self.ta_conf
|
||||
)
|
||||
|
||||
def test_fetch_endpoint(self):
|
||||
self.rp_profile.__str__()
|
||||
self.rp_profile.trust_mark_template_as_json
|
||||
url = reverse("oidcfed_fetch")
|
||||
c = Client()
|
||||
res = c.get(url, data={"sub": self.rp.sub})
|
||||
data = verify_jws(res.content.decode(), self.ta_conf.jwks_fed[0])
|
||||
|
||||
self.assertEqual(data['source_endpoint'], 'http://testserver//fetch')
|
||||
self.assertTrue(data["jwks"])
|
||||
|
||||
def test_list_endpoint(self):
|
||||
url = reverse("oidcfed_list")
|
||||
c = Client()
|
||||
res = c.get(url, data={})
|
||||
self.assertTrue(res.json())
|
||||
self.assertEqual(res.status_code, 200)
|
||||
|
||||
@override_settings(HTTP_CLIENT_SYNC=True)
|
||||
@patch("requests.get", return_value=EntityResponseNoIntermediate())
|
||||
def test_trust_chain_valid_no_intermediaries(self, mocked):
|
||||
|
||||
self.ta_conf.constraints = {"max_path_length": 0}
|
||||
self.ta_conf.save()
|
||||
|
||||
jwt = get_entity_configurations(self.ta_conf.sub)
|
||||
trust_anchor_ec = EntityConfiguration(jwt[0])
|
||||
|
||||
trust_chain = trust_chain_builder(
|
||||
subject=rp_onboarding_data["sub"],
|
||||
trust_anchor=trust_anchor_ec
|
||||
)
|
||||
self.assertTrue(trust_chain)
|
||||
self.assertTrue(trust_chain.final_metadata)
|
||||
|
||||
for i in trust_chain.tree_of_trust.values():
|
||||
for ec in i:
|
||||
self.assertTrue(ec.is_valid)
|
||||
|
||||
for ec in trust_chain.trust_path:
|
||||
self.assertTrue(ec.is_valid)
|
||||
|
||||
self.assertTrue(len(trust_chain.trust_path) == 2)
|
||||
self.assertTrue((len(trust_chain.trust_path) - 2) == trust_chain.max_path_len)
|
||||
|
||||
self.assertTrue(isinstance(trust_chain.exp, int))
|
||||
self.assertTrue(isinstance(trust_chain.exp_datetime, datetime.datetime))
|
||||
|
||||
def _create_federation_with_intermediary(self) -> EntityConfiguration:
|
||||
jwt = get_entity_configurations(self.ta_conf.sub)
|
||||
trust_anchor_ec = EntityConfiguration(jwt[0])
|
||||
|
||||
self.intermediate = FederationEntityConfiguration.objects.create(
|
||||
**intermediary_conf
|
||||
)
|
||||
|
||||
self.intermediate_desc = FederationDescendant.objects.create(
|
||||
**intermediary_onboarding_data
|
||||
)
|
||||
|
||||
FederationEntityAssignedProfile.objects.create(
|
||||
descendant=self.rp, profile=self.rp_profile, issuer=self.intermediate
|
||||
)
|
||||
self.rp_conf.authority_hints = [intermediary_conf["sub"]]
|
||||
self.rp_conf.save()
|
||||
return trust_anchor_ec
|
||||
|
||||
@override_settings(HTTP_CLIENT_SYNC=True)
|
||||
@patch("requests.get", return_value=EntityResponseWithIntermediate())
|
||||
def test_trust_chain_valid_with_intermediary(self, mocked):
|
||||
|
||||
trust_anchor_ec = self._create_federation_with_intermediary()
|
||||
|
||||
trust_chain = trust_chain_builder(
|
||||
subject=self.rp.sub,
|
||||
trust_anchor=trust_anchor_ec
|
||||
)
|
||||
|
||||
self.assertTrue(trust_chain)
|
||||
self.assertTrue(trust_chain.final_metadata)
|
||||
|
||||
for i in trust_chain.tree_of_trust.values():
|
||||
for ec in i:
|
||||
self.assertTrue(ec.is_valid)
|
||||
|
||||
for ec in trust_chain.trust_path:
|
||||
self.assertTrue(ec.is_valid)
|
||||
|
||||
self.assertTrue(len(trust_chain.trust_path) == 3)
|
||||
self.assertTrue((len(trust_chain.trust_path) - 2) == trust_chain.max_path_len)
|
||||
|
||||
tc_ser = trust_chain.serialize()
|
||||
_p0 = unpad_jwt_payload(tc_ser[0])
|
||||
_p1 = unpad_jwt_payload(tc_ser[1])
|
||||
_p2 = unpad_jwt_payload(tc_ser[2])
|
||||
_p3 = unpad_jwt_payload(tc_ser[3])
|
||||
|
||||
# Entity configurations
|
||||
self.assertEqual(_p0['iss'], _p0['sub'])
|
||||
self.assertEqual(_p3['iss'], _p3['sub'])
|
||||
|
||||
# Entity statements
|
||||
self.assertNotEqual(_p1['iss'], _p1['sub'])
|
||||
self.assertNotEqual(_p2['iss'], _p2['sub'])
|
||||
|
||||
# Chain consistency (positive)
|
||||
self.assertEqual(_p0['iss'], _p1['sub'])
|
||||
self.assertEqual(_p1['iss'], _p2['sub'])
|
||||
self.assertEqual(_p2['iss'], _p3['sub'])
|
||||
|
||||
# Chain consistency (negative)
|
||||
self.assertNotEqual(_p1['iss'], _p0['sub'])
|
||||
self.assertNotEqual(_p2['iss'], _p1['sub'])
|
||||
self.assertNotEqual(_p3['iss'], _p2['sub'])
|
||||
|
||||
dumps = dumps_statements_from_trust_chain_to_db(trust_chain)
|
||||
|
||||
self.assertTrue(isinstance(dumps, list) and len(dumps) == 5)
|
||||
|
||||
self.assertTrue("sub" in dumps[0].get_entity_configuration_as_obj().payload)
|
||||
|
||||
stored_trust_chain = TrustChain.objects.create(
|
||||
sub=trust_chain.subject,
|
||||
exp=trust_chain.exp_datetime,
|
||||
chain=trust_chain.serialize(),
|
||||
jwks = trust_chain.subject_configuration.jwks,
|
||||
metadata=trust_chain.final_metadata,
|
||||
parties_involved=[i.sub for i in trust_chain.trust_path],
|
||||
status="valid",
|
||||
trust_anchor=FetchedEntityStatement.objects.get(
|
||||
sub=trust_anchor_ec.sub, iss=trust_anchor_ec.sub
|
||||
),
|
||||
is_active=True,
|
||||
)
|
||||
|
||||
@override_settings(HTTP_CLIENT_SYNC=True)
|
||||
@patch("requests.get", return_value=EntityResponseWithIntermediateManyHints())
|
||||
def test_trust_chain_valid_with_intermediaries_many_authhints(self, mocked):
|
||||
|
||||
trust_anchor_ec = self._create_federation_with_intermediary()
|
||||
|
||||
self.rp_conf.authority_hints = [
|
||||
"http://intermediary-test",
|
||||
"http://that-faulty",
|
||||
]
|
||||
self.rp_conf.save()
|
||||
|
||||
trust_chain = trust_chain_builder(
|
||||
subject=self.rp.sub,
|
||||
trust_anchor=trust_anchor_ec
|
||||
)
|
||||
|
||||
for ec in trust_chain.trust_path:
|
||||
self.assertTrue(ec.is_valid)
|
||||
|
||||
self.assertTrue(len(trust_chain.trust_path) == 3)
|
||||
self.assertTrue((len(trust_chain.trust_path) - 2) == trust_chain.max_path_len)
|
||||
|
||||
@override_settings(HTTP_CLIENT_SYNC=True)
|
||||
@patch("requests.get", return_value=EntityResponseWithIntermediate())
|
||||
def test_trust_chain_valid_with_intermediaries_and_trust_mark_filter(self, mocked):
|
||||
|
||||
trust_anchor_ec = self._create_federation_with_intermediary()
|
||||
|
||||
# the RP exposes a trust marks in its entity configuration
|
||||
self.rp_conf.trust_marks = [
|
||||
FederationEntityAssignedProfile.objects.filter(descendant=self.rp)
|
||||
.first()
|
||||
.trust_mark
|
||||
]
|
||||
self.rp_conf.save()
|
||||
|
||||
trust_chain = trust_chain_builder(
|
||||
subject=self.rp.sub,
|
||||
trust_anchor=trust_anchor_ec,
|
||||
required_trust_marks=["https://www.spid.gov.it/certification/rp"],
|
||||
)
|
||||
|
||||
for ec in trust_chain.trust_path:
|
||||
self.assertTrue(ec.is_valid)
|
||||
|
||||
self.assertTrue(trust_chain.verified_trust_marks)
|
||||
self.assertTrue(isinstance(trust_chain.verified_trust_marks[0], TrustMark))
|
||||
|
||||
self.assertTrue(len(trust_chain.trust_path) == 3)
|
||||
self.assertTrue((len(trust_chain.trust_path) - 2) == trust_chain.max_path_len)
|
||||
|
||||
@override_settings(HTTP_CLIENT_SYNC=True)
|
||||
@patch("requests.get", return_value=EntityResponseWithIntermediate())
|
||||
def test_trust_chain_with_missing_trust_mark(self, mocked):
|
||||
|
||||
trust_anchor_ec = self._create_federation_with_intermediary()
|
||||
|
||||
with self.assertRaises(InvalidRequiredTrustMark):
|
||||
trust_chain = trust_chain_builder(
|
||||
subject=self.rp.sub,
|
||||
trust_anchor=trust_anchor_ec,
|
||||
required_trust_marks=["https://www.spid.gov.it/certification/rp"],
|
||||
)
|
||||
|
||||
@override_settings(HTTP_CLIENT_SYNC=True)
|
||||
@patch("requests.get", return_value=EntityResponseNoIntermediate())
|
||||
def test_trust_chain_valid_helpers(self, mocked):
|
||||
|
||||
gctc = get_or_create_trust_chain(
|
||||
subject=rp_conf["sub"],
|
||||
trust_anchor=self.ta_conf.sub,
|
||||
# TODO
|
||||
# required_trust_marks: list = []
|
||||
)
|
||||
|
||||
self.assertFalse(gctc.is_expired)
|
||||
self.assertTrue(gctc.is_valid)
|
||||
|
||||
@override_settings(HTTP_CLIENT_SYNC=True)
|
||||
@patch("requests.get", return_value=EntityResponseNoIntermediate())
|
||||
def test_resolve_endpoint(self, mocked):
|
||||
gctc = get_or_create_trust_chain(
|
||||
subject=rp_conf["sub"],
|
||||
trust_anchor=self.ta_conf.sub,
|
||||
# TODO
|
||||
# required_trust_marks: list = []
|
||||
)
|
||||
|
||||
url = reverse("oidcfed_resolve")
|
||||
|
||||
c = Client()
|
||||
res = c.get(url, data={
|
||||
"sub": self.rp.sub,
|
||||
"trust_anchor": self.ta_conf.sub
|
||||
}
|
||||
)
|
||||
self.assertTrue(res.status_code == 200)
|
||||
verify_jws(res.content.decode(), self.ta_conf.jwks_fed[0])
|
||||
|
||||
def test_trust_mark_status_endpoint(self):
|
||||
url = reverse("oidcfed_trust_mark_status")
|
||||
c = Client()
|
||||
# Legacy: sub + trust_mark_id -> 200 + JWT (application/trust-mark-status-response+jwt)
|
||||
res = c.post(
|
||||
url,
|
||||
data={
|
||||
"trust_mark_id": self.rp_assigned_profile.profile.profile_id,
|
||||
"sub": self.rp_assigned_profile.descendant.sub,
|
||||
},
|
||||
)
|
||||
self.assertEqual(res.status_code, 200)
|
||||
self.assertEqual(res.get("Content-Type"), "application/trust-mark-status-response+jwt")
|
||||
payload = unpad_jwt_payload(res.content.decode())
|
||||
self.assertEqual(payload.get("status"), "active")
|
||||
self.assertIn("trust_mark", payload)
|
||||
self.assertIn("iss", payload)
|
||||
self.assertIn("iat", payload)
|
||||
|
||||
# Draft 48: trust_mark JWT only -> 200 + JWT
|
||||
res = c.post(
|
||||
url,
|
||||
data={"trust_mark": self.rp_assigned_profile.trust_mark["trust_mark"]},
|
||||
)
|
||||
self.assertEqual(res.status_code, 200)
|
||||
self.assertEqual(res.get("Content-Type"), "application/trust-mark-status-response+jwt")
|
||||
payload = unpad_jwt_payload(res.content.decode())
|
||||
self.assertEqual(payload.get("status"), "active")
|
||||
|
||||
# Legacy: GET with sub + trust_mark_id -> 200 + JWT
|
||||
res = c.get(
|
||||
url,
|
||||
data={
|
||||
"trust_mark_id": self.rp_assigned_profile.profile.profile_id,
|
||||
"sub": self.rp_assigned_profile.descendant.sub,
|
||||
},
|
||||
)
|
||||
self.assertEqual(res.status_code, 200)
|
||||
self.assertEqual(res.get("Content-Type"), "application/trust-mark-status-response+jwt")
|
||||
|
||||
# Empty request -> 400 invalid_request
|
||||
res = c.get(url, data={})
|
||||
self.assertEqual(res.status_code, 400)
|
||||
self.assertEqual(res.json().get("error"), "invalid_request")
|
||||
|
||||
# Invalid trust_mark JWT -> 400
|
||||
res = c.get(
|
||||
url,
|
||||
data={"trust_mark": self.rp_assigned_profile.trust_mark["trust_mark"][1:]},
|
||||
)
|
||||
self.assertEqual(res.status_code, 400)
|
||||
|
||||
# trust_mark_id without sub -> 400
|
||||
res = c.get(
|
||||
url,
|
||||
data={"trust_mark_id": self.rp_assigned_profile.profile.profile_id},
|
||||
)
|
||||
self.assertEqual(res.status_code, 400)
|
||||
|
||||
# Unknown trust mark (wrong sub) -> 404 not_found
|
||||
res = c.get(
|
||||
url,
|
||||
data={
|
||||
"trust_mark_id": self.rp_assigned_profile.profile.profile_id,
|
||||
"sub": "https://nonexistent.example/",
|
||||
},
|
||||
)
|
||||
self.assertEqual(res.status_code, 404)
|
||||
self.assertEqual(res.json().get("error"), "not_found")
|
||||
|
||||
class TrustChainWithSignedJwksUriTest(TestCase):
|
||||
def setUp(self):
|
||||
self.ta_conf = FederationEntityConfiguration.objects.create(**ta_conf_data)
|
||||
|
||||
_rp_conf = copy.deepcopy(rp_conf)
|
||||
_rp_conf['metadata']['openid_relying_party'].pop('jwks')
|
||||
_rp_conf['metadata']['openid_relying_party']['signed_jwks_uri'] = f"{_rp_conf['sub']}signed_jwks.jose"
|
||||
self.rp_conf = FederationEntityConfiguration.objects.create(**_rp_conf)
|
||||
|
||||
self.rp_profile = FederationEntityProfile.objects.create(**RP_PROFILE)
|
||||
self.rp = FederationDescendant.objects.create(**rp_onboarding_data)
|
||||
|
||||
self.rp_assigned_profile = FederationEntityAssignedProfile.objects.create(
|
||||
descendant=self.rp, profile=self.rp_profile, issuer=self.ta_conf
|
||||
)
|
||||
|
||||
@override_settings(HTTP_CLIENT_SYNC=True)
|
||||
@patch("requests.get", return_value=EntityResponseNoIntermediateSignedJwksUri())
|
||||
def test_signed_jwks_uri(self, mocked):
|
||||
|
||||
self.ta_conf.constraints = {"max_path_length": 0}
|
||||
self.ta_conf.save()
|
||||
|
||||
jwt = get_entity_configurations(self.ta_conf.sub)
|
||||
trust_anchor_ec = EntityConfiguration(jwt[0])
|
||||
|
||||
trust_chain = trust_chain_builder(
|
||||
subject=rp_onboarding_data["sub"],
|
||||
trust_anchor=trust_anchor_ec
|
||||
)
|
||||
_jwks = get_jwks(
|
||||
trust_chain.final_metadata['openid_relying_party'],
|
||||
trust_chain.subject_configuration.jwks
|
||||
)
|
||||
self.assertTrue(
|
||||
verify_jws(_jwks, self.rp_conf.jwks_fed[0])
|
||||
)
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
|
||||
from copy import deepcopy
|
||||
from unittest.mock import patch
|
||||
|
||||
from django.test import TestCase
|
||||
from spid_cie_oidc.authority.tests.settings import (
|
||||
RP_CONF_AS_JSON,
|
||||
RP_METADATA_JWK1
|
||||
)
|
||||
from spid_cie_oidc.authority.utils import random_token
|
||||
from spid_cie_oidc.authority.validators import validate_entity_configuration
|
||||
from spid_cie_oidc.entity.exceptions import MissingAuthorityHintsClaim, NotDescendant
|
||||
from spid_cie_oidc.entity.jwtse import create_jws
|
||||
from spid_cie_oidc.entity.models import FederationEntityConfiguration
|
||||
from spid_cie_oidc.entity.tests.settings import ta_conf_data
|
||||
|
||||
JWS = create_jws(RP_CONF_AS_JSON, RP_METADATA_JWK1, typ="entity-statement+jwt")
|
||||
RP_CONF_AS_JSON_NO_HINTS = deepcopy(RP_CONF_AS_JSON)
|
||||
RP_CONF_AS_JSON_NO_HINTS.pop("authority_hints")
|
||||
JWS_NO_HINTS = create_jws(RP_CONF_AS_JSON_NO_HINTS, RP_METADATA_JWK1, typ="entity-statement+jwt")
|
||||
RP_CONF_AS_JSON_WRONG_HINTS = deepcopy(RP_CONF_AS_JSON)
|
||||
RP_CONF_AS_JSON_WRONG_HINTS["authority_hints"] = ["http://wrong.url.it"]
|
||||
JWS_WRONG_HINTS = create_jws(RP_CONF_AS_JSON_WRONG_HINTS, RP_METADATA_JWK1, typ="entity-statement+jwt")
|
||||
|
||||
class ValidatorTest(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.ta_conf = FederationEntityConfiguration.objects.create(**ta_conf_data)
|
||||
|
||||
@patch("spid_cie_oidc.authority.validators.get_entity_configurations", return_value = [JWS])
|
||||
def test_validator(self, mocked):
|
||||
validate_entity_configuration(["url_entity"])
|
||||
|
||||
@patch("spid_cie_oidc.authority.validators.get_entity_configurations", return_value = [JWS_NO_HINTS])
|
||||
def test_validator_no_hints(self, mocked):
|
||||
with self.assertRaises(MissingAuthorityHintsClaim):
|
||||
validate_entity_configuration(["url_entity"])
|
||||
|
||||
@patch("spid_cie_oidc.authority.validators.get_entity_configurations", return_value = [JWS_WRONG_HINTS])
|
||||
def test_validator_no_descendant(self, mocked):
|
||||
with self.assertRaises(NotDescendant):
|
||||
validate_entity_configuration(["url_entity"])
|
||||
|
||||
|
||||
class UtilityTests(TestCase):
|
||||
|
||||
def test_random_token(self):
|
||||
self.assertTrue(random_token())
|
||||
Vendored
+49
@@ -0,0 +1,49 @@
|
||||
from copy import deepcopy
|
||||
|
||||
from django.test import Client, TestCase, override_settings
|
||||
from django.urls import reverse
|
||||
from spid_cie_oidc.authority.models import FederationDescendant
|
||||
from spid_cie_oidc.authority.tests.settings import rp_onboarding_data
|
||||
from spid_cie_oidc.entity.models import FederationEntityConfiguration
|
||||
from spid_cie_oidc.entity.tests.settings import ta_conf_data
|
||||
|
||||
|
||||
class AdvanceEntityListing(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
FederationDescendant.objects.create(**rp_onboarding_data)
|
||||
rp_onboarding_data_local = deepcopy(rp_onboarding_data)
|
||||
rp_onboarding_data_local["sub"] = "http://rp-test.it/oidc/rplocal/"
|
||||
FederationDescendant.objects.create(**rp_onboarding_data_local)
|
||||
self.ta = FederationEntityConfiguration.objects.create(**ta_conf_data)
|
||||
|
||||
@override_settings(MAX_ENTRIES_PAGE=1)
|
||||
def test_advanced_entity_listing_1(self):
|
||||
url = reverse("oidcfed_advanced_entity_listing")
|
||||
data = {"page":2}
|
||||
res = Client().get(url, data)
|
||||
self.assertEqual(res.status_code, 200)
|
||||
self.assertEqual(res.json().get("iss"), "http://testserver/")
|
||||
self.assertEqual(len(res.json().get("entities")), 2)
|
||||
self.assertEqual(res.json().get("page"), 2)
|
||||
url_prev_page = reverse("oidcfed_advanced_entity_listing")
|
||||
self.assertEqual(res.json().get("prev_page_path"), f"{url_prev_page}?page=1")
|
||||
|
||||
@override_settings(MAX_ENTRIES_PAGE=1)
|
||||
def test_advanced_entity_listing_no_page(self):
|
||||
url = reverse("oidcfed_advanced_entity_listing")
|
||||
res = Client().get(url)
|
||||
self.assertEqual(res.status_code, 200)
|
||||
self.assertEqual(res.json().get("iss"), "http://testserver/")
|
||||
self.assertEqual(len(res.json().get("entities")), 2)
|
||||
self.assertEqual(res.json().get("page"), 1)
|
||||
url_next_page = reverse("oidcfed_advanced_entity_listing")
|
||||
self.assertEqual(res.json().get("next_page_path"), f"{url_next_page}?page=2")
|
||||
|
||||
def test_advanced_entity_listing_missing_trust_anchor(self):
|
||||
FederationEntityConfiguration.objects.all().delete()
|
||||
c = Client()
|
||||
url = reverse("oidcfed_advanced_entity_listing")
|
||||
res = c.get(url)
|
||||
self.assertEqual(res.status_code, 404)
|
||||
self.assertEqual(res.json().get("error"), "Missing trust anchor")
|
||||
@@ -0,0 +1,51 @@
|
||||
|
||||
from django.test import TestCase
|
||||
from spid_cie_oidc.authority.schemas.advanced_entity_list_endpoint import AdvancedEntityListRequest
|
||||
from spid_cie_oidc.authority.schemas.fetch_endpoint_request import FetchRequest
|
||||
from spid_cie_oidc.authority.schemas.list_endpoint import ListRequest
|
||||
from spid_cie_oidc.authority.schemas.trust_mark_status_endpoint import TrustMarkRequest
|
||||
from spid_cie_oidc.authority.tests.settings import (
|
||||
FETCH_REQUEST,
|
||||
LIST_REQUEST,
|
||||
TRUST_MARK_REQUEST,
|
||||
ADVANCED_LIST_REQUEST,
|
||||
TRUST_MARK_REQUEST_NO_SUB_ID,
|
||||
TRUST_MARK_REQUEST_NO_TRUST_MARK,
|
||||
TRUST_MARK_REQUEST_TRUST_MARK_NO_ID_NO_TRUST_MARK,
|
||||
TRUST_MARK_REQUEST_TRUST_MARK_NO_SUB,
|
||||
TRUST_MARK_REQUEST_TRUST_MARK_NO_SUB_NO_TRUST_MARK,
|
||||
)
|
||||
|
||||
class SchemaTest(TestCase):
|
||||
|
||||
def setUp(self) -> None:
|
||||
return super().setUp()
|
||||
|
||||
def test_fetch_request(self):
|
||||
FetchRequest(**FETCH_REQUEST)
|
||||
|
||||
def test_list_request(self):
|
||||
ListRequest(**LIST_REQUEST)
|
||||
|
||||
def test_trust_mark_request(self):
|
||||
TrustMarkRequest(**TRUST_MARK_REQUEST)
|
||||
|
||||
def test_trust_mark_request_no_sub_id(self):
|
||||
TrustMarkRequest(**TRUST_MARK_REQUEST_NO_SUB_ID)
|
||||
|
||||
def test_trust_mark_request_no_rust_mark(self):
|
||||
TrustMarkRequest(**TRUST_MARK_REQUEST_NO_TRUST_MARK)
|
||||
|
||||
def test_trust_mark_request_no_sub(self):
|
||||
TrustMarkRequest(**TRUST_MARK_REQUEST_TRUST_MARK_NO_SUB)
|
||||
|
||||
def test_trust_mark_request_no_id_no_tust_mark(self):
|
||||
# Schema allows optional fields; view returns 400 if neither (sub+id) nor trust_mark provided
|
||||
TrustMarkRequest(**TRUST_MARK_REQUEST_TRUST_MARK_NO_ID_NO_TRUST_MARK)
|
||||
|
||||
def test_trust_mark_request_no_sub_no_tust_mark(self):
|
||||
# Schema allows optional fields; view returns 400 if neither (sub+id) nor trust_mark provided
|
||||
TrustMarkRequest(**TRUST_MARK_REQUEST_TRUST_MARK_NO_SUB_NO_TRUST_MARK)
|
||||
|
||||
def test_advanced_list_request(self):
|
||||
AdvancedEntityListRequest(**ADVANCED_LIST_REQUEST)
|
||||
Reference in New Issue
Block a user