feat: link local library

This commit is contained in:
gabdevele
2026-06-17 20:43:56 +02:00 Unverified
parent 9a770a2af0
commit db59882f33
327 changed files with 22274 additions and 1 deletions
@@ -0,0 +1,138 @@
from copy import deepcopy
from spid_cie_oidc.entity.utils import exp_from_now, iat_now
# TODO: we need factory function to get fresh now
IAT = iat_now()
EXP = exp_from_now()
CLAIMS_SPID = {
"userinfo": {
"given_name": {"values": ["str", "str"]},
"family_name": None,
"birthdate": {"value": "str"},
},
}
CLAIMS_CIE = {
"userinfo": {
"given_name": {"values": ["str", "str"]},
"family_name": None,
"birthdate": {"value": "str"},
},
"id_token": {
"given_name": {"values": ["str", "str"]},
"family_name": None,
"birthdate": {"value": "str"},
},
}
AUTHN_REQUEST_SPID = {
"client_id": "https://rp.cie.it/callback1/",
"response_type": "code",
"scope": ["openid", "offline_access"],
"code_challenge": "codeChallenge",
"code_challenge_method": "S256",
"nonce": "12345678123456781234567812345678inpiu",
"prompt": "consent",
"redirect_uri": "https://rp.cie.it/callback1/",
"acr_values": ["https://www.spid.gov.it/SpidL2", "https://www.spid.gov.it/SpidL1"],
"claims": CLAIMS_SPID,
"state": "fyZiOL9Lf2CeKuNT2JzxiLRDink0uPcd",
"ui_locales": ["codice1", "codice2", "codice3"],
"sub": "https://rp.cie.it/",
"iss": "https://op.spid.agid.gov.it/",
"aud": ["https://rp.spid.agid.gov.it/auth"],
"iat": IAT,
"exp": EXP,
"jti": "a72d5df0-2415-4c7c-a44f-3988b354040b",
}
AUTHN_REQUEST_SPID_NO_CLIENT_ID = deepcopy(AUTHN_REQUEST_SPID)
AUTHN_REQUEST_SPID_NO_CLIENT_ID.pop("client_id")
AUTHN_REQUEST_SPID_NO_CORRECT_CLAIMS = deepcopy(AUTHN_REQUEST_SPID)
AUTHN_REQUEST_SPID_NO_CORRECT_CLAIMS["claims"]["userinfo"][
"given_name"
]["values"] = ["str"]
AUTHN_REQUEST_SPID_NO_CODE_CHALLENGE = deepcopy(AUTHN_REQUEST_SPID)
AUTHN_REQUEST_SPID_NO_CODE_CHALLENGE.pop("code_challenge")
AUTHN_REQUEST_SPID_NO_CODE_CHALLENGE_METHOD = deepcopy(AUTHN_REQUEST_SPID)
AUTHN_REQUEST_SPID_NO_CODE_CHALLENGE_METHOD.pop("code_challenge_method")
AUTHN_REQUEST_SPID_NO_CORRECT_CODE_CHALLENGE_METHOD = deepcopy(AUTHN_REQUEST_SPID)
AUTHN_REQUEST_SPID_NO_CORRECT_CODE_CHALLENGE_METHOD["code_challenge_method"] = "S257"
AUTHN_REQUEST_SPID_NO_NONCE = deepcopy(AUTHN_REQUEST_SPID)
AUTHN_REQUEST_SPID_NO_NONCE.pop("nonce")
AUTHN_REQUEST_SPID_NO_CORRECT_NONCE = deepcopy(AUTHN_REQUEST_SPID)
AUTHN_REQUEST_SPID_NO_CORRECT_NONCE["nonce"] = "toosmall"
AUTHN_REQUEST_SPID_NO_PROMPT = deepcopy(AUTHN_REQUEST_SPID)
AUTHN_REQUEST_SPID_NO_PROMPT.pop("prompt")
AUTHN_REQUEST_SPID_NO_CORRECT_PROMPT = deepcopy(AUTHN_REQUEST_SPID)
AUTHN_REQUEST_SPID_NO_CORRECT_PROMPT["prompt"] = "no_correct"
AUTHN_REQUEST_SPID_NO_REDIRECT_URL = deepcopy(AUTHN_REQUEST_SPID)
AUTHN_REQUEST_SPID_NO_REDIRECT_URL.pop("redirect_uri")
AUTHN_REQUEST_SPID_NO_CORRECT_REDIRECT_URL = deepcopy(AUTHN_REQUEST_SPID)
AUTHN_REQUEST_SPID_NO_CORRECT_REDIRECT_URL["redirect_uri"] = "https://rp"
AUTHN_REQUEST_SPID_NO_RESPONSE_TYPE = deepcopy(AUTHN_REQUEST_SPID)
AUTHN_REQUEST_SPID_NO_RESPONSE_TYPE.pop("response_type")
AUTHN_REQUEST_SPID_NO_CORRECT_RESPONSE_TYPE = deepcopy(AUTHN_REQUEST_SPID)
AUTHN_REQUEST_SPID_NO_CORRECT_RESPONSE_TYPE["response_type"] = "codecode"
AUTHN_REQUEST_SPID_NO_SCOPE = deepcopy(AUTHN_REQUEST_SPID)
AUTHN_REQUEST_SPID_NO_SCOPE.pop("scope")
AUTHN_REQUEST_SPID_NO_CORRECT_SCOPE = deepcopy(AUTHN_REQUEST_SPID)
AUTHN_REQUEST_SPID_NO_CORRECT_SCOPE["scope"] = ["offline_access"]
AUTHN_REQUEST_SPID_NO_ACR_VALUES = deepcopy(AUTHN_REQUEST_SPID)
AUTHN_REQUEST_SPID_NO_ACR_VALUES.pop("acr_values")
AUTHN_REQUEST_SPID_NO_CORRECT_ACR_VALUES = deepcopy(AUTHN_REQUEST_SPID)
AUTHN_REQUEST_SPID_NO_CORRECT_ACR_VALUES["acr_values"] = [
"https://www.spid.gov.it/SpidL4",
"https://www.spid.gov.it/SpidL1",
]
AUTHN_REQUEST_SPID_NO_STATE = deepcopy(AUTHN_REQUEST_SPID)
AUTHN_REQUEST_SPID_NO_STATE.pop("state")
AUTHN_REQUEST_SPID_NO_CORRECT_STATE = deepcopy(AUTHN_REQUEST_SPID)
AUTHN_REQUEST_SPID_NO_CORRECT_STATE["state"] = "toosmall"
AUTHN_REQUEST_SPID_NO_CORRECT_UI_LOCALES = deepcopy(AUTHN_REQUEST_SPID)
AUTHN_REQUEST_SPID_NO_CORRECT_UI_LOCALES["ui_locales"] = "nocorrect"
AUTHN_REQUEST_CIE = deepcopy(AUTHN_REQUEST_SPID)
AUTHN_REQUEST_CIE["scope"] = ["openid", "offline_access", "email", "profile"]
AUTHN_REQUEST_CIE["prompt"] = "consent login"
AUTHN_REQUEST_CIE["claims"] = CLAIMS_CIE
AUTHN_REQUEST_CIE_NO_ACR_VALUES = deepcopy(AUTHN_REQUEST_CIE)
AUTHN_REQUEST_CIE_NO_ACR_VALUES.pop("acr_values")
AUTHN_REQUEST_CIE_NO_CORRECT_ACR_VALUES = deepcopy(AUTHN_REQUEST_CIE)
AUTHN_REQUEST_CIE_NO_CORRECT_ACR_VALUES["acr_values"] = "CIE_L3"
AUTHN_REQUEST_CIE_NO_PROMPT = deepcopy(AUTHN_REQUEST_CIE)
AUTHN_REQUEST_CIE_NO_PROMPT.pop("prompt")
AUTHN_REQUEST_CIE_NO_CORRECT_PROMPT = deepcopy(AUTHN_REQUEST_CIE)
AUTHN_REQUEST_CIE_NO_CORRECT_PROMPT["prompt"] = "verify"
AUTHN_REQUEST_CIE_NO_SCOPE = deepcopy(AUTHN_REQUEST_CIE)
AUTHN_REQUEST_CIE_NO_SCOPE.pop("scope")
AUTHN_REQUEST_CIE_NO_CORRECT_SCOPE = deepcopy(AUTHN_REQUEST_CIE)
AUTHN_REQUEST_CIE_NO_CORRECT_SCOPE["scope"] = "openid"
@@ -0,0 +1,52 @@
from copy import deepcopy
AUTHN_RESPONSE_SPID = {
"code": "usDwMnEzJPpG5oaV8x3j&",
"state": "fyZiOL9Lf2CeKuNT2JzxiLRDink0uPcd&",
}
AUTHN_RESPONSE_SPID_NO_CODE = deepcopy(AUTHN_RESPONSE_SPID)
AUTHN_RESPONSE_SPID_NO_CODE.pop("code")
AUTHN_RESPONSE_SPID_NO_STATE = deepcopy(AUTHN_RESPONSE_SPID)
AUTHN_RESPONSE_SPID_NO_STATE.pop("state")
AUTHN_RESPONSE_SPID_NO_CORRECT_STATE = deepcopy(AUTHN_RESPONSE_SPID)
AUTHN_RESPONSE_SPID_NO_CORRECT_STATE["state"] = "tooshort"
AUTHN_RESPONSE_CIE = deepcopy(AUTHN_RESPONSE_SPID)
AUTHN_RESPONSE_CIE["iss"] = "https://idserver.servizicie.interno.gov.it"
AUTHN_RESPONSE_CIE_NO_ISS = deepcopy(AUTHN_RESPONSE_CIE)
AUTHN_RESPONSE_CIE_NO_ISS.pop("iss")
AUTHN_RESPONSE_CIE_NO_CORRECT_ISS = deepcopy(AUTHN_RESPONSE_CIE)
AUTHN_RESPONSE_CIE_NO_CORRECT_ISS["iss"] = ""
AUTHN_ERROR_RESPONSE = {
"error_description": "request%20malformata&",
"code": "usDwMnEzJPpG5oaV8x3j&",
"state": "fyZiOL9Lf2CeKuNT2JzxiLRDink0uPcd&",
}
AUTHN_ERROR_RESPONSE_SPID = deepcopy(AUTHN_ERROR_RESPONSE)
AUTHN_ERROR_RESPONSE_SPID["error"] = "invalid_request"
AUTHN_ERROR_RESPONSE_SPID_NO_CODE = deepcopy(AUTHN_ERROR_RESPONSE)
AUTHN_ERROR_RESPONSE_SPID_NO_CODE.pop("code")
AUTHN_ERROR_RESPONSE_SPID_NO_STATE = deepcopy(AUTHN_ERROR_RESPONSE)
AUTHN_ERROR_RESPONSE_SPID_NO_STATE.pop("state")
AUTHN_ERROR_RESPONSE_SPID_NO_CORRECT_STATE = deepcopy(AUTHN_ERROR_RESPONSE)
AUTHN_ERROR_RESPONSE_SPID_NO_CORRECT_STATE["state"] = "tooshort"
AUTHN_ERROR_RESPONSE_CIE = deepcopy(AUTHN_ERROR_RESPONSE)
AUTHN_ERROR_RESPONSE_CIE["error"] = "unsupported_response_type"
AUTHN_ERROR_RESPONSE_CIE["iss"] = "https://idserver.servizicie.interno.gov.it"
AUTHN_ERROR_RESPONSE_CIE_NO_ISS = deepcopy(AUTHN_ERROR_RESPONSE_CIE)
AUTHN_ERROR_RESPONSE_CIE_NO_ISS.pop("iss")
AUTHN_ERROR_RESPONSE_CIE_NO_CORRECT_ISS = deepcopy(AUTHN_ERROR_RESPONSE_CIE)
AUTHN_ERROR_RESPONSE_CIE_NO_CORRECT_ISS["iss"] = "//idserver.servizicie.interno.gov.it"
@@ -0,0 +1,32 @@
from copy import deepcopy
INTROSPECTION_REQUEST = {
"client_assertion": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI.LVyRDPVJ",
"client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
"client_id": "https://rp.spid.agid.gov.it",
"token": "eyJhbGciOiJSUzI1NiJ9.eyJleHAiOjE0MTg3MDI0MTQsImF1ZCI6W.FXDtEzDL",
}
INTROSPECTION_REQUEST_NO_CLIENT_ASSERTION = deepcopy(INTROSPECTION_REQUEST)
INTROSPECTION_REQUEST_NO_CLIENT_ASSERTION.pop("client_assertion")
INTROSPECTION_REQUEST_NO_CORRECT_CLIENT_ASSERTION = deepcopy(INTROSPECTION_REQUEST)
INTROSPECTION_REQUEST_NO_CORRECT_CLIENT_ASSERTION["client_assertion"] = ".payload.sig"
INTROSPECTION_REQUEST_NO_CLIENT_ASSERTION_TYPE = deepcopy(INTROSPECTION_REQUEST)
INTROSPECTION_REQUEST_NO_CLIENT_ASSERTION_TYPE.pop("client_assertion_type")
INTROSPECTION_REQUEST_NO_CORRECT_CLIENT_ASSERTION_TYPE = deepcopy(INTROSPECTION_REQUEST)
INTROSPECTION_REQUEST_NO_CORRECT_CLIENT_ASSERTION_TYPE["client_assertion_type"] = ""
INTROSPECTION_REQUEST_NO_CLIENT_ID = deepcopy(INTROSPECTION_REQUEST)
INTROSPECTION_REQUEST_NO_CLIENT_ID.pop("client_id")
INTROSPECTION_REQUEST_NO_CORRECT_CLIENT_ID = deepcopy(INTROSPECTION_REQUEST)
INTROSPECTION_REQUEST_NO_CORRECT_CLIENT_ID["client_id"] = "https//rp.spid.agid.gov.it"
INTROSPECTION_REQUEST_NO_TOKEN = deepcopy(INTROSPECTION_REQUEST)
INTROSPECTION_REQUEST_NO_TOKEN.pop("token")
INTROSPECTION_REQUEST_NO_CORRECT_TOKEN = deepcopy(INTROSPECTION_REQUEST)
INTROSPECTION_REQUEST_NO_CORRECT_TOKEN["token"] = ".sign"
@@ -0,0 +1,69 @@
from copy import deepcopy
INTROSPECTION_RESPONSE = {
"active": True,
# "scope": ["openid"],
# "exp": 162545274,
# "sub": "OP-1234567890",
# "client_id": "https://rp.agid.gov.it/",
# "iss": "https://op.spid.agid.gov.it/",
# "aud": ["https://rp.spid.agid.gov.it/auth"],
}
INTROSPECTION_RESPONSE_NO_ACTIVE = deepcopy(INTROSPECTION_RESPONSE)
INTROSPECTION_RESPONSE_NO_ACTIVE.pop("active")
INTROSPECTION_RESPONSE_NO_CORRECT_ACTIVE = deepcopy(INTROSPECTION_RESPONSE)
INTROSPECTION_RESPONSE_NO_CORRECT_ACTIVE["active"] = "ciao"
INTROSPECTION_RESPONSE_NO_CORRECT_SCOPE = deepcopy(INTROSPECTION_RESPONSE)
INTROSPECTION_RESPONSE_NO_CORRECT_SCOPE["scope"] = "scope"
INTROSPECTION_RESPONSE_NO_CORRECT_EXP = deepcopy(INTROSPECTION_RESPONSE)
INTROSPECTION_RESPONSE_NO_CORRECT_EXP["exp"] = "exp"
INTROSPECTION_RESPONSE_NO_CORRECT_SUB = deepcopy(INTROSPECTION_RESPONSE)
INTROSPECTION_RESPONSE_NO_CORRECT_SUB["sub"] = []
INTROSPECTION_RESPONSE_NO_CORRECT_CLIENT_ID = deepcopy(INTROSPECTION_RESPONSE)
INTROSPECTION_RESPONSE_NO_CORRECT_CLIENT_ID["client_id"] = "https/op.agid.gov.it/"
INTROSPECTION_RESPONSE_NO_CORRECT_ISS = deepcopy(INTROSPECTION_RESPONSE)
INTROSPECTION_RESPONSE_NO_CORRECT_ISS["iss"] = ""
INTROSPECTION_RESPONSE_NO_CORRECT_AUD = deepcopy(INTROSPECTION_RESPONSE)
INTROSPECTION_RESPONSE_NO_CORRECT_AUD["aud"] = "https://rp.spid.agid.gov.it/auth"
INTROSPECTION_ERROR_RESPONSE = {
"error": "invalid_request",
"error_description": "descrizione dell’errore",
}
INTROSPECTION_ERROR_RESPONSE_SPID_NO_ERROR = deepcopy(INTROSPECTION_ERROR_RESPONSE)
INTROSPECTION_ERROR_RESPONSE_SPID_NO_ERROR.pop("error")
INTROSPECTION_ERROR_RESPONSE_SPID_NO_CORRECT_ERROR = deepcopy(
INTROSPECTION_ERROR_RESPONSE
)
INTROSPECTION_ERROR_RESPONSE_SPID_NO_CORRECT_ERROR["error"] = "invalid_token"
INTROSPECTION_ERROR_RESPONSE_CIE_NO_ERROR = deepcopy(INTROSPECTION_ERROR_RESPONSE)
INTROSPECTION_ERROR_RESPONSE_CIE_NO_ERROR.pop("error")
INTROSPECTION_ERROR_RESPONSE_CIE_NO_CORRECT_ERROR = deepcopy(
INTROSPECTION_ERROR_RESPONSE
)
INTROSPECTION_ERROR_RESPONSE_CIE_NO_CORRECT_ERROR["error"] = "error"
INTROSPECTION_ERROR_RESPONSE_NO_ERROR_DESCRIPTION = deepcopy(
INTROSPECTION_ERROR_RESPONSE
)
INTROSPECTION_ERROR_RESPONSE_NO_ERROR_DESCRIPTION.pop("error_description")
INTROSPECTION_ERROR_RESPONSE_NO_CORRECT_ERROR_DESCRIPTION = deepcopy(
INTROSPECTION_ERROR_RESPONSE
)
INTROSPECTION_ERROR_RESPONSE_NO_CORRECT_ERROR_DESCRIPTION["error_description"] = []
@@ -0,0 +1,32 @@
from copy import deepcopy
REVOCATION_REQUEST = {
"client_assertion": "eyJhbGciOiJIUzpXVCJ9.eyJzdWIdHJ1ZX0.LVyRDPVJm0S9q",
"client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
"client_id": "https://rp.spid.agid.gov.it",
"token": "eyJhbGciOiJSUzI1NiJ9.eyR9.FXDtEzDLbTHzFNroW7w27RLk",
}
REVOCATION_REQUEST_NO_CLIENT_ASSERTION = deepcopy(REVOCATION_REQUEST)
REVOCATION_REQUEST_NO_CLIENT_ASSERTION.pop("client_assertion")
REVOCATION_REQUEST_NO_CORRECT_CLIENT_ASSERTION = deepcopy(REVOCATION_REQUEST)
REVOCATION_REQUEST_NO_CORRECT_CLIENT_ASSERTION["client_assertion"] = ".payload."
REVOCATION_REQUEST_NO_CLIENT_ASSERTION_TYPE = deepcopy(REVOCATION_REQUEST)
REVOCATION_REQUEST_NO_CLIENT_ASSERTION_TYPE.pop("client_assertion_type")
REVOCATION_REQUEST_NO_CORRECT_CLIENT_ASSERTION_TYPE = deepcopy(REVOCATION_REQUEST)
REVOCATION_REQUEST_NO_CORRECT_CLIENT_ASSERTION_TYPE["client_assertion_type"] = ""
REVOCATION_REQUEST_NO_CLIENT_ID = deepcopy(REVOCATION_REQUEST)
REVOCATION_REQUEST_NO_CLIENT_ID.pop("client_id")
REVOCATION_REQUEST_NO_CORRECT_CLIENT_ID = deepcopy(REVOCATION_REQUEST)
REVOCATION_REQUEST_NO_CORRECT_CLIENT_ID["client_id"] = ""
REVOCATION_REQUEST_NO_TOKEN = deepcopy(REVOCATION_REQUEST)
REVOCATION_REQUEST_NO_TOKEN.pop("token")
REVOCATION_REQUEST_NO_CORRECT_TOKEN = deepcopy(REVOCATION_REQUEST)
REVOCATION_REQUEST_NO_CORRECT_TOKEN["token"] = ".."
@@ -0,0 +1,20 @@
from copy import deepcopy
REVOCATION_RESPONSE_CIE = {
"error": "unauthorized_client",
"error_description": "description of the error",
}
REVOCATION_RESPONSE_CIE_NO_ERROR = deepcopy(REVOCATION_RESPONSE_CIE)
REVOCATION_RESPONSE_CIE_NO_ERROR.pop("error")
REVOCATION_RESPONSE_CIE_NO_CORRECT_ERROR = deepcopy(REVOCATION_RESPONSE_CIE)
REVOCATION_RESPONSE_CIE_NO_CORRECT_ERROR["error"] = []
REVOCATION_RESPONSE_CIE_NO_ERROR_DESCRIPTION = deepcopy(REVOCATION_RESPONSE_CIE)
REVOCATION_RESPONSE_CIE_NO_ERROR_DESCRIPTION.pop("error_description")
REVOCATION_RESPONSE_CIE_NO_CORRECT_ERROR_DESCRIPTION = deepcopy(REVOCATION_RESPONSE_CIE)
REVOCATION_RESPONSE_CIE_NO_CORRECT_ERROR_DESCRIPTION["error_description"] = [
"error description"
]
@@ -0,0 +1,141 @@
op_conf_priv_jwk = {
"use": "sig",
"kty": "RSA",
"kid": "dB67gL7ck3TFiIAf7N6_7SHvqk0MDYMEQcoGGlkUAAw",
"n": "01_4aI2Lu5ggsElmRkE_S_a83V_szXU0txV4db2hmJ8HR1Y2s7PsZZ5-emGpnTydGrR3n-QExeEEIcFt_a06Ryiink34RQcKoGXUDBMBU0Bu8G7NcZ99YX6yeG9wFi4xs-WviTPmtPqijkz6jm1_ltWDcwbktfkraIRKKggZaEl9ldtsFr2wSpin3AXuGIdeJ0hZqhF92ODBLGjJlaIL9KlwopDy56adReVnraawSdrxmuPGj78IEADNAme2nQNvv9UCu0FkAn5St1bKds3Gpv26W0kjr1gZLsmQrj9lTcDk_KbAwfEY__P7se62kusoSuKMTQqUG1TQpUY7oFGSdw",
"e": "AQAB",
"d": "AxvyR3dtisDeGjm6K2ZiS_fBJ3B1xz_mGptSPkkfy2LrdH0sKNCItaXzLlGpcQqnNPFaoRt1hoOcz_JMb-LQbKOIYNO8xycnXNyildrhthvIhfjbRMSXz4tRjLv25hyf1omWX2pIBnl5UqaHOPkbW1igqlx7mMGlhdAMVznvRb1oJOXxPtSdlVOhqT5ohn4BJZcJ85TKm_E49KUKUsz_xkd3BlYnUaiuEu-VQbC0u61iH-N017wg4ZQn9eXQgAzFdSNI2GQ7IH76l00iUu-y9oT2ld4WHGYMmsZBJgaQZnu2Yj4IMb5NjQz2VAOTU844RXP7-7Y5rWsS1oewfWSHAQ",
"p": "9dvm96S4wBrwzs73DOG8eV6sWEN13ZJNLa4tKzJvonOLG_8Z9Rshnfg_HcYDm_mqRD-nFC-8JKufnNaZbZuO_hDiA6UkvlZMGePxoN7nueHGfAqZ9lRQX0Vpp2Ac480jJgBLOhwgjkySRI5Ck-enTGabkxVN_LJSU9FC54TW6KE",
"q": "3BfwsumO62vhekd2gm97Uk1XFOM5UXmb1esdFnZ_RZRw1tDUB2irTxLJSqECCZbMWRoFRB3k-17LAOMaITUqv8g-83zdCmR3gpO71ahbdEfkGGKQYL7WmMNv3YvSMY5lN4_mCEz8R_OCz0_H7bip0Es_KAl5TSXjnVTvaACnLBc",
}
op_conf = {
"sub": "http://op-test/oidc/op/",
"default_exp": 2880,
"default_signature_alg": "RS256",
"authority_hints": ["http://op-test/oidc/op/"],
"jwks_fed": [op_conf_priv_jwk],
"jwks_core": [op_conf_priv_jwk],
"trust_marks": [],
"trust_mark_issuers": {},
"entity_type": "openid_provider",
"metadata": {
"openid_provider": {
"authorization_endpoint": "http://op-test/oidc/op/authorization/",
"token_endpoint": "http://op-test/oidc/op/token",
"userinfo_endpoint": "http://op-test/oidc/op/userinfo/",
"introspection_endpoint": "http://op-test/oidc/op/introspection/",
"revocation_endpoint": "http://op-test/oidc/op/revocation/",
"claims_parameter_supported": True,
"contacts": ["[email protected]"],
"client_registration_types_supported": ["automatic"],
"request_authentication_methods_supported": {"ar": ["request_object"]},
"acr_values_supported": [
"https://www.spid.gov.it/SpidL1",
"https://www.spid.gov.it/SpidL2",
"https://www.spid.gov.it/SpidL3",
],
"claims_supported": [
"https://attributes.eid.gov.it/spid_code",
"given_name",
"family_name",
"place_of_birth",
"birthdate",
"gender",
"https://attributes.eid.gov.it/company_name",
"https://attributes.eid.gov.it/registered_office",
"https://attributes.eid.gov.it/fiscal_number",
"https://attributes.eid.gov.it/company_fiscal_number",
"https://attributes.eid.gov.it/vat_number",
"document_details",
"phone_number",
"email",
"https://attributes.eid.gov.it/e_delivery_service",
"https://attributes.eid.gov.it/eid_exp_date",
"address"
],
"grant_types_supported": ["authorization_code", "refresh_token"],
"id_token_signing_alg_values_supported": ["RS256", "ES256"],
"issuer": "http://op-test/oidc/op/",
"jwks": {
"keys": [
{
"use": "sig",
"kty": "RSA",
"n": "01_4aI2Lu5ggsElmRkE_S_a83V_szXU0txV4db2hmJ8HR1Y2s7PsZZ5-emGpnTydGrR3n-QExeEEIcFt_a06Ryiink34RQcKoGXUDBMBU0Bu8G7NcZ99YX6yeG9wFi4xs-WviTPmtPqijkz6jm1_ltWDcwbktfkraIRKKggZaEl9ldtsFr2wSpin3AXuGIdeJ0hZqhF92ODBLGjJlaIL9KlwopDy56adReVnraawSdrxmuPGj78IEADNAme2nQNvv9UCu0FkAn5St1bKds3Gpv26W0kjr1gZLsmQrj9lTcDk_KbAwfEY__P7se62kusoSuKMTQqUG1TQpUY7oFGSdw",
"e": "AQAB",
"kid": "dB67gL7ck3TFiIAf7N6_7SHvqk0MDYMEQcoGGlkUAAw",
}
]
},
"scopes_supported": ["openid", "offline_access"],
"logo_uri": "http://op-test/oidc/op/statics/logo.svg",
"organization_name": "SPID OIDC identity provider",
"op_policy_uri": "http://op-test/oidc/op/en/website/legal-information/",
"request_parameter_supported": True,
"request_uri_parameter_supported": True,
"require_request_uri_registration": True,
"response_types_supported": ["code"],
"subject_types_supported": ["pairwise", "public"],
"token_endpoint_auth_methods_supported": ["private_key_jwt"],
"token_endpoint_auth_signing_alg_values_supported": [
"RS256",
"RS384",
"RS512",
"ES256",
"ES384",
"ES512",
],
"userinfo_encryption_alg_values_supported": [
"RSA-OAEP",
"RSA-OAEP-256",
"ECDH-ES",
"ECDH-ES+A128KW",
"ECDH-ES+A192KW",
"ECDH-ES+A256KW",
],
"userinfo_encryption_enc_values_supported": [
"A128CBC-HS256",
"A192CBC-HS384",
"A256CBC-HS512",
"A128GCM",
"A192GCM",
"A256GCM",
],
"userinfo_signing_alg_values_supported": [
"RS256",
"RS384",
"RS512",
"ES256",
"ES384",
"ES512",
],
"request_object_encryption_alg_values_supported": [
"RSA-OAEP",
"RSA-OAEP-256",
"ECDH-ES",
"ECDH-ES+A128KW",
"ECDH-ES+A192KW",
"ECDH-ES+A256KW",
],
"request_object_encryption_enc_values_supported": [
"A128CBC-HS256",
"A192CBC-HS384",
"A256CBC-HS512",
"A128GCM",
"A192GCM",
"A256GCM",
],
"request_object_signing_alg_values_supported": [
"RS256",
"RS384",
"RS512",
"ES256",
"ES384",
"ES512",
],
}
},
"constraints": {},
"is_active": True,
}
@@ -0,0 +1,353 @@
from copy import deepcopy
from django.contrib.auth import get_user_model
from django.test import Client, TestCase, override_settings
from django.urls import reverse
from spid_cie_oidc.authority.tests.settings import RP_METADATA, RP_METADATA_JWK1, rp_onboarding_data
from django.utils import timezone
from spid_cie_oidc.entity.jwtse import create_jws, unpad_jwt_payload, verify_jws
from spid_cie_oidc.entity.models import (
FederationEntityConfiguration,
FetchedEntityStatement,
TrustChain,
)
from spid_cie_oidc.entity.tests.settings import TA_SUB
from spid_cie_oidc.entity.utils import datetime_from_timestamp, exp_from_now, iat_now
from spid_cie_oidc.entity.utils import get_jwks
from spid_cie_oidc.provider.models import IssuedToken, OidcSession
from spid_cie_oidc.provider.tests.settings import op_conf, op_conf_priv_jwk
from spid_cie_oidc.relying_party.utils import random_string
RP_SUB = rp_onboarding_data["sub"]
class AuthnRequestTest(TestCase):
def setUp(self):
self.REQUEST_OBJECT_PAYLOAD = {
"client_id": RP_SUB,
"sub": RP_SUB,
"iss": RP_SUB,
"response_type": "code",
"scope": ["openid"],
"code_challenge": "qWJlMe0xdbXrKxTm72EpH659bUxAxw80",
"code_challenge_method": "S256",
"nonce": random_string(),
"prompt": "consent login",
"redirect_uri": f"{RP_SUB}callback/",
"acr_values": ["https://www.spid.gov.it/SpidL1", "https://www.spid.gov.it/SpidL2"],
"claims": {
"id_token": {"family_name": {"essential": True}, "email": {"essential": True}},
"userinfo": {"given_name": None, "family_name": None, "email": None},
},
"state": random_string(),
"aud": ["https://op.spid.agid.gov.it/auth"],
"iat": iat_now(),
"exp": exp_from_now(),
"jti": "a72d5df0-2415-4c7c-a44f-3988b354040b",
}
self.user = get_user_model().objects.create(
username="test",
first_name="test",
last_name="test",
email="[email protected]",
is_staff= False,
attributes={
"family_name": "rossi",
"username": "unique_value",
"fiscal_number": "a7s6da87d6a87sd6as78d",
"email": "[email protected]",
},
)
self.user.set_password("test")
self.user.save()
self.op_conf = FederationEntityConfiguration.objects.create(**op_conf)
self.ta_fes = FetchedEntityStatement.objects.create(
sub=TA_SUB,
iss=TA_SUB,
exp=datetime_from_timestamp(exp_from_now(33)),
iat=datetime_from_timestamp(iat_now()),
)
self.trust_chain = TrustChain.objects.create(
sub=RP_SUB,
exp=datetime_from_timestamp(exp_from_now(33)),
jwks = [],
metadata=RP_METADATA,
status="valid",
trust_anchor=self.ta_fes,
is_active=True,
)
@override_settings(OIDCFED_TRUST_ANCHORS=[TA_SUB])
def test_auth_request_unknown_error(self):
jws = create_jws(self.REQUEST_OBJECT_PAYLOAD, RP_METADATA_JWK1)
client = Client()
TrustChain.objects.all().delete()
url = reverse("oidc_provider_authnrequest")
res = client.get(url, {"request": jws})
self.assertTrue(res.status_code == 302)
self.assertTrue("error=invalid_request" in res.url)
@override_settings(OIDCFED_TRUST_ANCHORS=[TA_SUB])
@override_settings(OIDCFED_DEFAULT_PROVIDER_PROFILE="cie")
def test_auth_request_id_token_claim(self):
jws = create_jws(self.REQUEST_OBJECT_PAYLOAD, RP_METADATA_JWK1)
client = Client()
url = reverse("oidc_provider_authnrequest")
res = client.get(url, {"request": jws})
self.assertTrue(res.status_code == 200)
self.assertIn("username", res.content.decode())
self.assertIn("password", res.content.decode())
res = client.post(
url, {"username": "test", "password": "test", "authz_request_object": jws}
)
self.assertFalse("error" in res.content.decode())
self.assertTrue(res.status_code == 302)
consent_page_url = res.url
res = client.get(consent_page_url)
self.assertTrue("agree" in res.content.decode())
self.assertFalse("error" in res.content.decode())
res = client.post(consent_page_url, {"agree": True})
issued_token = IssuedToken.objects.all().first()
verify_jws(issued_token.id_token, op_conf_priv_jwk)
id_token = unpad_jwt_payload(issued_token.id_token)
self.assertEqual(id_token.get("family_name"), "rossi")
self.assertEqual(id_token.get("email"), "[email protected]")
@override_settings(OIDCFED_TRUST_ANCHORS=[TA_SUB])
def test_auth_no_request(self):
client = Client()
url = reverse("oidc_provider_authnrequest")
res = client.get(url, {})
self.assertTrue(res.status_code == 400)
@override_settings(OIDCFED_TRUST_ANCHORS=[TA_SUB])
def test_auth_request_ok(self):
jws = create_jws(self.REQUEST_OBJECT_PAYLOAD, RP_METADATA_JWK1)
client = Client()
url = reverse("oidc_provider_authnrequest")
res = client.get(url, {"request": jws})
self.assertTrue(res.status_code == 200)
self.assertIn("username", res.content.decode())
self.assertIn("password", res.content.decode())
res = client.post(
url, {"username": "test", "password": "test", "authz_request_object": jws}
)
self.assertFalse("error" in res.content.decode())
self.assertTrue(res.status_code == 302)
consent_page_url = res.url
res = client.get(consent_page_url)
self.assertTrue("agree" in res.content.decode())
self.assertFalse("error" in res.content.decode())
res = client.post(consent_page_url, {"agree": True})
self.assertTrue(res.status_code == 302)
self.assertTrue("code" in res.url)
@override_settings(OIDCFED_TRUST_ANCHORS=[TA_SUB])
def test_auth_request_user_rejected_consent(self):
jws = create_jws(self.REQUEST_OBJECT_PAYLOAD, RP_METADATA_JWK1)
client = Client()
url = reverse("oidc_provider_authnrequest")
res = client.get(url, {"request": jws})
self.assertTrue(res.status_code == 200)
self.assertIn("username", res.content.decode())
self.assertIn("password", res.content.decode())
res = client.post(
url, {"username": "test", "password": "test", "authz_request_object": jws}
)
self.assertFalse("error" in res.content.decode())
self.assertTrue(res.status_code == 302)
consent_page_url = res.url
res = client.get(consent_page_url)
self.assertTrue("agree" in res.content.decode())
self.assertFalse("error" in res.content.decode())
res = client.post(consent_page_url, {"agree": False})
self.assertTrue(res.status_code == 302)
# TODO: this is not normative
self.assertTrue("error=rejected_by_user" in res.url)
@override_settings(OIDCFED_TRUST_ANCHORS=[TA_SUB])
def test_auth_request_no_session_in_post_consent(self):
jws = create_jws(self.REQUEST_OBJECT_PAYLOAD, RP_METADATA_JWK1)
client = Client()
url = reverse("oidc_provider_authnrequest")
res = client.get(url, {"request": jws})
self.assertTrue(res.status_code == 200)
self.assertIn("username", res.content.decode())
self.assertIn("password", res.content.decode())
res = client.post(
url, {"username": "test", "password": "test", "authz_request_object": jws}
)
self.assertFalse("error" in res.content.decode())
self.assertTrue(res.status_code == 302)
consent_page_url = res.url
res = client.get(consent_page_url)
self.assertTrue("agree" in res.content.decode())
self.assertFalse("error" in res.content.decode())
OidcSession.objects.all().delete()
res = client.post(consent_page_url, {"agree": True})
self.assertTrue(res.status_code == 403)
@override_settings(OIDCFED_TRUST_ANCHORS=[TA_SUB])
def test_auth_request_no_session_in_get_consent(self):
jws = create_jws(self.REQUEST_OBJECT_PAYLOAD, RP_METADATA_JWK1)
client = Client()
url = reverse("oidc_provider_authnrequest")
res = client.get(url, {"request": jws})
self.assertTrue(res.status_code == 200)
self.assertIn("username", res.content.decode())
self.assertIn("password", res.content.decode())
res = client.post(
url,
{
"username": "test",
"password": "test",
"authz_request_object": jws
}
)
self.assertFalse("error" in res.content.decode())
self.assertTrue(res.status_code == 302)
consent_page_url = res.url
OidcSession.objects.all().delete()
res = client.get(consent_page_url)
self.assertTrue(res.status_code == 403)
@override_settings(OIDCFED_TRUST_ANCHORS=[TA_SUB])
def test_auth_request_auth_code_already_used(self):
jws = create_jws(self.REQUEST_OBJECT_PAYLOAD, RP_METADATA_JWK1)
client = Client()
url = reverse("oidc_provider_authnrequest")
res = client.get(url, {"request": jws})
self.assertTrue(res.status_code == 200)
self.assertIn("username", res.content.decode())
self.assertIn("password", res.content.decode())
res = client.post(
url, {"username": "test", "password": "test", "authz_request_object": jws}
)
self.assertFalse("error" in res.content.decode())
self.assertTrue(res.status_code == 302)
session = OidcSession.objects.all().first()
IssuedToken.objects.create(session=session, expires=timezone.localtime())
consent_page_url = res.url
res = client.get(consent_page_url)
self.assertTrue(res.status_code == 403)
@override_settings(OIDCFED_TRUST_ANCHORS=[TA_SUB])
def test_auth_request_wrong_login(self):
jws = create_jws(self.REQUEST_OBJECT_PAYLOAD, RP_METADATA_JWK1)
client = Client()
url = reverse("oidc_provider_authnrequest")
res = client.get(url, {"request": jws})
self.assertTrue(res.status_code == 200)
self.assertIn("username", res.content.decode())
self.assertIn("password", res.content.decode())
res = client.post(
url, {"username": "notest", "password": "test", "authz_request_object": jws}
)
self.assertIn("error", res.content.decode())
@override_settings(OIDCFED_TRUST_ANCHORS=[TA_SUB])
def test_auth_request_preexistent_authz(self):
jws = create_jws(self.REQUEST_OBJECT_PAYLOAD, RP_METADATA_JWK1)
client = Client()
url = reverse("oidc_provider_authnrequest")
res = client.get(url, {"request": jws})
self.assertTrue(res.status_code == 200)
self.assertIn("username", res.content.decode())
self.assertIn("password", res.content.decode())
res = client.post(
url, {"username": "test", "password": "test", "authz_request_object": jws}
)
res = client.get(url, {"request": jws})
self.assertTrue(res.status_code == 302)
self.assertIn("error=invalid_request", res.url)
self.assertIn("state", res.url)
@override_settings(OIDCFED_TRUST_ANCHORS=[TA_SUB])
def test_auth_request_trust_chain_no_active(self):
self.trust_chain.is_active = False
self.trust_chain.save()
jws = create_jws(self.REQUEST_OBJECT_PAYLOAD, RP_METADATA_JWK1)
client = Client()
url = reverse("oidc_provider_authnrequest")
res = client.get(url, {"request": jws})
self.assertTrue(res.status_code == 302)
self.assertIn("error=invalid_request", res.url)
self.assertIn("state", res.url)
@override_settings(OIDCFED_TRUST_ANCHORS=[TA_SUB])
def test_auth_request_invalid_jwk(self):
jws = create_jws(self.REQUEST_OBJECT_PAYLOAD, RP_METADATA_JWK1)
get_jwks(self.trust_chain.metadata['openid_relying_party'])[0][
"kid"
] = "31ALfVXx9dcAMMHCVvh42qLTlanBL_r6BTnD5uMDzFT"
self.trust_chain.save()
client = Client()
url = reverse("oidc_provider_authnrequest")
res = client.get(url, {"request": jws})
self.assertTrue(res.status_code == 302)
self.assertIn("error=invalid_request", res.url)
self.assertIn("state", res.url)
get_jwks(self.trust_chain.metadata['openid_relying_party'])[0][
"kid"
] = RP_METADATA_JWK1['kid']
self.trust_chain.save()
@override_settings(OIDCFED_TRUST_ANCHORS=[TA_SUB])
def test_auth_request_no_correct_payload(self):
NO_CORRECT_OBJECT_PAYLOAD = deepcopy(self.REQUEST_OBJECT_PAYLOAD)
NO_CORRECT_OBJECT_PAYLOAD["response_type"] = "test"
jws = create_jws(NO_CORRECT_OBJECT_PAYLOAD, RP_METADATA_JWK1)
client = Client()
url = reverse("oidc_provider_authnrequest")
res = client.get(url, {"request": jws})
self.assertTrue(res.status_code == 302)
self.assertIn("error", res.url)
self.assertIn("state", res.url)
@override_settings(OIDCFED_TRUST_ANCHORS=[TA_SUB])
def test_auth_request_invalid_session(self):
client = Client()
url = reverse("oidc_provider_consent")
res = client.get(url)
self.assertTrue(res.status_code == 403)
res = client.post(url)
self.assertTrue(res.status_code == 403)
@override_settings(OIDCFED_TRUST_ANCHORS=[TA_SUB])
def test_auth_request_no_correct_refresh_request(self):
local_payload = deepcopy(self.REQUEST_OBJECT_PAYLOAD)
local_payload["scope"] = "openid offline_access"
local_payload["prompt"] = "login"
jws = create_jws(local_payload, RP_METADATA_JWK1)
client = Client()
url = reverse("oidc_provider_authnrequest")
res = client.get(url, {"request": jws})
self.assertTrue(res.status_code == 403)
@override_settings(OIDCFED_TRUST_ANCHORS=[TA_SUB])
def test_auth_request_user_staff(self):
self.user.is_staff = True
self.user.save()
jws = create_jws(self.REQUEST_OBJECT_PAYLOAD, RP_METADATA_JWK1)
client = Client()
url = reverse("oidc_provider_authnrequest")
res = client.post(
url, {"username": "test", "password": "test", "authz_request_object": jws}
)
self.assertTrue(res.status_code == 302)
self.assertTrue("/oidc/op/rp-test/landing/" == res.url)
@override_settings(OIDCFED_TRUST_ANCHORS=[TA_SUB])
def test_auth_request_no_correct_authz_request(self):
self.user.is_staff = True
self.user.save()
create_jws(self.REQUEST_OBJECT_PAYLOAD, RP_METADATA_JWK1)
client = Client()
url = reverse("oidc_provider_authnrequest")
res = client.post(
url, {"username": "test", "password": "test", "authz_request_object": {}}
)
self.assertTrue(res.status_code == 403)
@@ -0,0 +1,154 @@
import logging
from django.test import TestCase
from pydantic import ValidationError
from spid_cie_oidc.provider.schemas.authn_requests import (
AuthenticationRequestCie,
AuthenticationRequestSpid,
)
from .authn_request_settings import (
AUTHN_REQUEST_CIE,
AUTHN_REQUEST_CIE_NO_ACR_VALUES,
AUTHN_REQUEST_CIE_NO_CORRECT_ACR_VALUES,
AUTHN_REQUEST_CIE_NO_CORRECT_PROMPT,
AUTHN_REQUEST_CIE_NO_CORRECT_SCOPE,
AUTHN_REQUEST_CIE_NO_PROMPT,
AUTHN_REQUEST_CIE_NO_SCOPE,
AUTHN_REQUEST_SPID,
AUTHN_REQUEST_SPID_NO_CLIENT_ID,
AUTHN_REQUEST_SPID_NO_CODE_CHALLENGE,
AUTHN_REQUEST_SPID_NO_CODE_CHALLENGE_METHOD,
AUTHN_REQUEST_SPID_NO_CORRECT_ACR_VALUES,
AUTHN_REQUEST_SPID_NO_CORRECT_CLAIMS,
AUTHN_REQUEST_SPID_NO_CORRECT_CODE_CHALLENGE_METHOD,
AUTHN_REQUEST_SPID_NO_CORRECT_NONCE,
AUTHN_REQUEST_SPID_NO_CORRECT_PROMPT,
AUTHN_REQUEST_SPID_NO_CORRECT_REDIRECT_URL,
AUTHN_REQUEST_SPID_NO_CORRECT_RESPONSE_TYPE,
AUTHN_REQUEST_SPID_NO_CORRECT_SCOPE,
AUTHN_REQUEST_SPID_NO_CORRECT_STATE,
AUTHN_REQUEST_SPID_NO_CORRECT_UI_LOCALES,
AUTHN_REQUEST_SPID_NO_NONCE,
AUTHN_REQUEST_SPID_NO_REDIRECT_URL,
AUTHN_REQUEST_SPID_NO_RESPONSE_TYPE,
AUTHN_REQUEST_SPID_NO_SCOPE,
AUTHN_REQUEST_SPID_NO_STATE,
)
logger = logging.getLogger(__name__)
class AuthRequestTest(TestCase):
def test_validate_spid(self):
AuthenticationRequestSpid(**AUTHN_REQUEST_SPID)
def test_validate_spid_no_client_id(self):
with self.assertRaises(ValidationError):
AuthenticationRequestSpid(**AUTHN_REQUEST_SPID_NO_CLIENT_ID)
def test_validate_spid_no_correct_claims(self):
with self.assertRaises(ValidationError):
AuthenticationRequestSpid(**AUTHN_REQUEST_SPID_NO_CORRECT_CLAIMS)
def test_validate_spid_no_code_challenge(self):
with self.assertRaises(ValidationError):
AuthenticationRequestSpid(**AUTHN_REQUEST_SPID_NO_CODE_CHALLENGE)
def test_validate_spid_no_code_challenge_method(self):
with self.assertRaises(ValidationError):
AuthenticationRequestSpid(**AUTHN_REQUEST_SPID_NO_CODE_CHALLENGE_METHOD)
def test_validate_spid_no_correct_code_challenge_method(self):
with self.assertRaises(ValidationError):
AuthenticationRequestSpid(
**AUTHN_REQUEST_SPID_NO_CORRECT_CODE_CHALLENGE_METHOD
)
def test_validate_spid_no_nonce(self):
with self.assertRaises(ValidationError):
AuthenticationRequestSpid(**AUTHN_REQUEST_SPID_NO_NONCE)
def test_validate_spid_no_correct_nonce(self):
with self.assertRaises(ValidationError):
AuthenticationRequestSpid(**AUTHN_REQUEST_SPID_NO_CORRECT_NONCE)
# removed, relaxed with the GAIN-PoC integration
# def test_validate_spid_no_prompt(self):
# with self.assertRaises(ValidationError):
# AuthenticationRequestSpid(**AUTHN_REQUEST_SPID_NO_PROMPT)
def test_validate_spid_no_correct_prompt(self):
with self.assertRaises(ValidationError):
AuthenticationRequestSpid(**AUTHN_REQUEST_SPID_NO_CORRECT_PROMPT)
def test_validate_spid_no_redirect_url(self):
with self.assertRaises(ValidationError):
AuthenticationRequestSpid(**AUTHN_REQUEST_SPID_NO_REDIRECT_URL)
def test_validate_spid_no_correct_redirect_url(self):
with self.assertRaises(ValidationError):
AuthenticationRequestSpid(**AUTHN_REQUEST_SPID_NO_CORRECT_REDIRECT_URL)
def test_validate_spid_no_response_type(self):
with self.assertRaises(ValidationError):
AuthenticationRequestSpid(**AUTHN_REQUEST_SPID_NO_RESPONSE_TYPE)
def test_validate_spid_no_correct_response_type(self):
with self.assertRaises(ValidationError):
AuthenticationRequestSpid(**AUTHN_REQUEST_SPID_NO_CORRECT_RESPONSE_TYPE)
def test_validate_spid_no_scope(self):
with self.assertRaises(ValidationError):
AuthenticationRequestSpid(**AUTHN_REQUEST_SPID_NO_SCOPE)
def test_validate_spid_no_correct_scope(self):
with self.assertRaises(ValidationError):
AuthenticationRequestSpid(**AUTHN_REQUEST_SPID_NO_CORRECT_SCOPE)
# def test_validate_spid_no_acr_values(self):
# with self.assertRaises(ValidationError):
# AuthenticationRequestSpid(**AUTHN_REQUEST_SPID_NO_ACR_VALUES)
def test_validate_spid_no_correct_acr_values(self):
with self.assertRaises(ValidationError):
AuthenticationRequestSpid(**AUTHN_REQUEST_SPID_NO_CORRECT_ACR_VALUES)
def test_validate_spid_no_state(self):
with self.assertRaises(ValidationError):
AuthenticationRequestSpid(**AUTHN_REQUEST_SPID_NO_STATE)
def test_validate_spid_no_correct_state(self):
with self.assertRaises(ValidationError):
AuthenticationRequestSpid(**AUTHN_REQUEST_SPID_NO_CORRECT_STATE)
def test_validate_spid_no_correct_ui_locales(self):
with self.assertRaises(ValidationError):
AuthenticationRequestSpid(**AUTHN_REQUEST_SPID_NO_CORRECT_UI_LOCALES)
def test_validate_cie(self):
AuthenticationRequestCie(**AUTHN_REQUEST_CIE)
def test_validate_cie_no_acr_values(self):
with self.assertRaises(ValidationError):
AuthenticationRequestSpid(**AUTHN_REQUEST_CIE_NO_ACR_VALUES)
def test_validate_cie_no_correct_acr_values(self):
with self.assertRaises(ValidationError):
AuthenticationRequestSpid(**AUTHN_REQUEST_CIE_NO_CORRECT_ACR_VALUES)
def test_validate_cie_no_prompt(self):
with self.assertRaises(ValidationError):
AuthenticationRequestSpid(**AUTHN_REQUEST_CIE_NO_PROMPT)
def test_validate_cie_no_correct_prompt(self):
with self.assertRaises(ValidationError):
AuthenticationRequestSpid(**AUTHN_REQUEST_CIE_NO_CORRECT_PROMPT)
def test_validate_cie_no_scope(self):
with self.assertRaises(ValidationError):
AuthenticationRequestSpid(**AUTHN_REQUEST_CIE_NO_SCOPE)
def test_validate_cie_no_correct_scope(self):
with self.assertRaises(ValidationError):
AuthenticationRequestSpid(**AUTHN_REQUEST_CIE_NO_CORRECT_SCOPE)
@@ -0,0 +1,191 @@
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
from spid_cie_oidc.accounts.models import User
from spid_cie_oidc.authority.tests.settings import (
RP_METADATA,
RP_METADATA_JWK1,
rp_conf
)
from spid_cie_oidc.entity.jwtse import create_jws, verify_jws
from spid_cie_oidc.entity.models import (
FederationEntityConfiguration,
FetchedEntityStatement,
TrustChain
)
from spid_cie_oidc.entity.tests.settings import TA_SUB
from spid_cie_oidc.entity.utils import (
datetime_from_timestamp,
exp_from_now,
iat_now
)
from spid_cie_oidc.provider.models import IssuedToken, OidcSession
from spid_cie_oidc.provider.tests.settings import op_conf, op_conf_priv_jwk
RP_SUB = rp_conf["sub"]
RP_CLIENT_ID = rp_conf["metadata"]["openid_relying_party"]["client_id"]
class RefreshTokenTest(TestCase):
def setUp(self):
self.op_local_conf = deepcopy(op_conf)
FederationEntityConfiguration.objects.create(**self.op_local_conf)
self.ta_fes = FetchedEntityStatement.objects.create(
sub=TA_SUB,
iss=TA_SUB,
exp=datetime_from_timestamp(exp_from_now(33)),
iat=datetime_from_timestamp(iat_now()),
)
self.trust_chain = TrustChain.objects.create(
sub=RP_SUB,
exp=datetime_from_timestamp(exp_from_now(33)),
jwks=[],
metadata=RP_METADATA,
status="valid",
trust_anchor=self.ta_fes,
is_active=True,
)
self.jwt_auds = [op_conf["sub"], "http://testserver/oidc/op/", "http://testserver/oidc/op/token"]
CLIENT_ASSERTION = {
"iss": RP_SUB,
"sub": RP_SUB,
"aud": self.jwt_auds,
"exp": exp_from_now(),
"iat": iat_now(),
"jti": "jti",
}
self.ca_jws = create_jws(CLIENT_ASSERTION, RP_METADATA_JWK1)
refresh_token = {
"iss": self.op_local_conf["sub"],
"sub": RP_SUB,
"aud": self.jwt_auds,
"client_id": RP_CLIENT_ID,
"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="",
nonce="",
authz_request={"scope": "offline_access", "prompt": "consent", "nonce": "123",
"acr_values": ["https://www.spid.gov.it/SpidL2", "https://www.spid.gov.it/SpidL1"]},
client_id=RP_SUB,
auth_code="code",
)
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"])
@override_settings(OIDCFED_PROVIDER_PROFILE="spid")
def test_grant_refresh_token_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)
refresh_token = verify_jws(res.json().get("refresh_token"), op_conf_priv_jwk)
self.assertEqual(refresh_token["aud"], RP_CLIENT_ID)
self.assertEqual(refresh_token["iss"], self.op_local_conf["sub"])
@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(
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"
)
time.sleep(2)
res = client.post(url, request)
self.assertTrue(res.status_code == 400)
@@ -0,0 +1,83 @@
import logging
from django.test import TestCase
from pydantic import ValidationError
from spid_cie_oidc.provider.schemas.authn_response import (
AuthenticationErrorResponse,
AuthenticationErrorResponseCie,
AuthenticationResponse,
AuthenticationResponseCie,
)
from .authn_responses_settings import (
AUTHN_ERROR_RESPONSE_CIE,
AUTHN_ERROR_RESPONSE_CIE_NO_CORRECT_ISS,
AUTHN_ERROR_RESPONSE_CIE_NO_ISS,
AUTHN_ERROR_RESPONSE_SPID,
AUTHN_ERROR_RESPONSE_SPID_NO_CODE,
AUTHN_ERROR_RESPONSE_SPID_NO_CORRECT_STATE,
AUTHN_ERROR_RESPONSE_SPID_NO_STATE,
AUTHN_RESPONSE_CIE,
AUTHN_RESPONSE_CIE_NO_CORRECT_ISS,
AUTHN_RESPONSE_CIE_NO_ISS,
AUTHN_RESPONSE_SPID,
AUTHN_RESPONSE_SPID_NO_CODE,
AUTHN_RESPONSE_SPID_NO_CORRECT_STATE,
AUTHN_RESPONSE_SPID_NO_STATE,
)
logger = logging.getLogger(__name__)
class AuthResponseTest(TestCase):
def test_validate_response_spid(self):
AuthenticationResponse(**AUTHN_RESPONSE_SPID)
def test_validate_response_spid_no_code(self):
with self.assertRaises(ValidationError):
AuthenticationResponse(**AUTHN_RESPONSE_SPID_NO_CODE)
def test_validate_response_spid_no_state(self):
with self.assertRaises(ValidationError):
AuthenticationResponse(**AUTHN_RESPONSE_SPID_NO_STATE)
def test_validate_response_spid_no_correct_state(self):
with self.assertRaises(ValidationError):
AuthenticationResponse(**AUTHN_RESPONSE_SPID_NO_CORRECT_STATE)
def test_validate_response_cie(self):
AuthenticationResponseCie(**AUTHN_RESPONSE_CIE)
def test_validate_response_cie_no_iss(self):
with self.assertRaises(ValidationError):
AuthenticationResponseCie(**AUTHN_RESPONSE_CIE_NO_ISS)
def test_validate_response_cie_no_correct_iss(self):
with self.assertRaises(ValidationError):
AuthenticationResponseCie(**AUTHN_RESPONSE_CIE_NO_CORRECT_ISS)
def test_validate_error_response_spid(self):
AuthenticationErrorResponse(**AUTHN_ERROR_RESPONSE_SPID)
def test_validate_error_response_spid_no_code(self):
with self.assertRaises(ValidationError):
AuthenticationErrorResponse(**AUTHN_ERROR_RESPONSE_SPID_NO_CODE)
def test_validate_error_response_spid_no_state(self):
with self.assertRaises(ValidationError):
AuthenticationErrorResponse(**AUTHN_ERROR_RESPONSE_SPID_NO_STATE)
def test_validate_error_response_spid_no_correct_state(self):
with self.assertRaises(ValidationError):
AuthenticationErrorResponse(**AUTHN_ERROR_RESPONSE_SPID_NO_CORRECT_STATE)
def test_validate_error_response_cie(self):
AuthenticationErrorResponseCie(**AUTHN_ERROR_RESPONSE_CIE)
def test_validate_error_response_spid_no_iss(self):
with self.assertRaises(ValidationError):
AuthenticationErrorResponseCie(**AUTHN_ERROR_RESPONSE_CIE_NO_ISS)
def test_validate_error_response_spid_no_correct_iss(self):
with self.assertRaises(ValidationError):
AuthenticationErrorResponseCie(**AUTHN_ERROR_RESPONSE_CIE_NO_CORRECT_ISS)
@@ -0,0 +1,111 @@
from copy import deepcopy
from django.test import Client, TestCase
from django.urls import reverse
from spid_cie_oidc.accounts.models import User
from spid_cie_oidc.authority.tests.settings import (
RP_METADATA,
rp_onboarding_data
)
from spid_cie_oidc.entity.jwtse import create_jws
from spid_cie_oidc.entity.models import (
FederationEntityConfiguration,
FetchedEntityStatement,
TrustChain
)
from spid_cie_oidc.entity.tests.settings import TA_SUB
from spid_cie_oidc.entity.utils import (
datetime_from_timestamp,
exp_from_now,
iat_now
)
from spid_cie_oidc.provider.models import IssuedToken, OidcSession
from spid_cie_oidc.provider.tests.settings import op_conf, op_conf_priv_jwk
class UserInfoEndpointTest(TestCase):
def setUp(self):
self.RP_SUB = rp_onboarding_data["sub"]
self.op_local_conf = deepcopy(op_conf)
FederationEntityConfiguration.objects.create(**self.op_local_conf)
self.ta_fes = FetchedEntityStatement.objects.create(
sub=TA_SUB,
iss=TA_SUB,
exp=datetime_from_timestamp(exp_from_now(33)),
iat=datetime_from_timestamp(iat_now()),
)
def define_db(self):
session = OidcSession.objects.create(
user=User.objects.create(
username = "username", attributes = {"email" : "[email protected]"}
),
user_uid="",
nonce="",
authz_request={
"scope": "openid", "nonce": "123", "claims":{
"userinfo":{"email": None}
}
},
client_id=self.RP_SUB,
)
access_token = {
"iss": self.RP_SUB,
"sub": op_conf["sub"],
"aud": [self.RP_SUB],
"client_id": self.RP_SUB,
"scope": "openid",
}
jwt_at = create_jws(access_token, op_conf_priv_jwk, typ="at+jwt")
iss_token_data = dict(
session=session,
access_token= jwt_at,
id_token= "id_token",
expires=datetime_from_timestamp(exp_from_now())
)
IssuedToken.objects.create(**iss_token_data)
headers= {
"HTTP_AUTHORIZATION": f"Bearer {jwt_at}"
}
return headers
def test_userinfo_endpoint_no_header(self):
client = Client()
url = reverse("oidc_provider_userinfo_endpoint")
res = client.get(url, {})
self.assertTrue(res.status_code == 403)
def test_userinfo_endpoint_no_issued_token_session(self):
client = Client()
url = reverse("oidc_provider_userinfo_endpoint")
headers= {
"HTTP_AUTHORIZATION": "Bearer dC34Pf6kdG"
}
res = client.get(url, data = {}, **headers)
self.assertTrue(res.status_code == 403)
def test_userinfo_endpoint_no_tc(self):
headers = self.define_db()
client = Client()
url = reverse("oidc_provider_userinfo_endpoint")
res = client.get(url, data = {}, **headers)
self.assertTrue(res.status_code == 403)
def test_userinfo_endpoint_ok(self):
headers = self.define_db()
self.trust_chain = TrustChain.objects.create(
sub=self.RP_SUB,
exp=datetime_from_timestamp(exp_from_now(33)),
jwks = [],
metadata=RP_METADATA,
status="valid",
trust_anchor=self.ta_fes,
is_active=True,
)
client = Client()
url = reverse("oidc_provider_userinfo_endpoint")
res = client.get(url, data = {}, **headers)
self.assertTrue(res.status_code == 200)
@@ -0,0 +1,124 @@
from copy import deepcopy
from django.test import Client, TestCase
from django.urls import reverse
from spid_cie_oidc.accounts.models import User
from spid_cie_oidc.authority.tests.settings import (
RP_METADATA,
rp_conf
)
from spid_cie_oidc.entity.jwtse import create_jws
from spid_cie_oidc.entity.models import (
FederationEntityConfiguration,
FetchedEntityStatement,
TrustChain
)
from spid_cie_oidc.entity.tests.settings import TA_SUB
from spid_cie_oidc.entity.utils import (
datetime_from_timestamp,
exp_from_now,
iat_now
)
from spid_cie_oidc.provider.models import IssuedToken, OidcSession
from spid_cie_oidc.provider.tests.settings import (
op_conf,
op_conf_priv_jwk
)
class IntrospectionEndpointTest(TestCase):
def setUp(self):
self.RP_SUB = rp_conf["sub"]
self.RP_CLIENT_ID = rp_conf["metadata"]["openid_relying_party"]["client_id"]
self.jwt_auds = [op_conf["sub"], "http://testserver/oidc/op/", "http://testserver/oidc/op/introspection"]
CLIENT_ASSERTION = {
"iss": self.RP_SUB,
"sub": self.RP_SUB,
"aud": self.jwt_auds,
"exp": exp_from_now(),
"iat": iat_now(),
"jti": "jti",
}
self.ca_jws = create_jws(CLIENT_ASSERTION, rp_conf["jwks_core"][0])
token = {
"iss": self.RP_SUB,
"sub": op_conf["sub"],
"aud": self.jwt_auds,
"client_id": self.RP_SUB,
"scope": "openid",
}
self.jwt_token = create_jws(token, op_conf_priv_jwk, typ="at+jwt")
session = OidcSession.objects.create(
user=User.objects.create(username = "username"),
user_uid="",
nonce="",
authz_request={"scope": "openid"},
client_id=self.RP_SUB,
)
iss_token_data = dict(
session=session,
access_token= self.jwt_token,
id_token= "id_token",
refresh_token= "refresh_token",
expires=datetime_from_timestamp(exp_from_now())
)
IssuedToken.objects.create(**iss_token_data)
self.op_local_conf = deepcopy(op_conf)
FederationEntityConfiguration.objects.create(**self.op_local_conf)
self.ta_fes = FetchedEntityStatement.objects.create(
sub=TA_SUB,
iss=TA_SUB,
exp=datetime_from_timestamp(exp_from_now(33)),
iat=datetime_from_timestamp(iat_now()),
)
self.trust_chain = TrustChain.objects.create(
sub=self.RP_SUB,
exp=datetime_from_timestamp(exp_from_now(33)),
jwks = [],
metadata=RP_METADATA,
status="valid",
trust_anchor=self.ta_fes,
is_active=True,
)
def test_introspection_endpoint(self):
client = Client()
url = reverse("oidc_provider_introspection_endpoint")
request = {
"client_assertion" : self.ca_jws,
"client_assertion_type" : "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
"client_id" : self.RP_SUB,
"token" : self.jwt_token
}
res = client.post(url, request)
self.assertTrue(res.status_code == 200)
self.assertTrue("openid" in res.content.decode())
def test_introspection_endpoint_get(self):
client = Client()
url = reverse("oidc_provider_introspection_endpoint")
request = {
"client_assertion" : self.ca_jws,
"client_assertion_type" : "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
"client_id" : self.RP_SUB,
"token" : self.jwt_token
}
res = client.get(url, request)
self.assertTrue(res.status_code == 400)
def test_introspection_endpoint_validation_error(self):
client = Client()
url = reverse("oidc_provider_introspection_endpoint")
request = {
"client_assertion" : self.ca_jws,
"client_assertion_type" : "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
"token" : self.jwt_token
}
res = client.post(url, request)
self.assertTrue(res.status_code == 400)
self.assertTrue(res.json()["error"] == "invalid_request")
@@ -0,0 +1,147 @@
import logging
from django.test import TestCase
from pydantic import ValidationError
from spid_cie_oidc.provider.schemas.jwt import JwtStructure
from spid_cie_oidc.provider.schemas.token_requests import (
TokenAuthnCodeRequest,
TokenRefreshRequest,
)
from .token_request_settings import (
JWT_CLIENT_ASSERTION,
JWT_CLIENT_ASSERTION_NO_AUD,
JWT_CLIENT_ASSERTION_NO_CORRECT_AUD,
JWT_CLIENT_ASSERTION_NO_CORRECT_EXP,
JWT_CLIENT_ASSERTION_NO_CORRECT_IAT,
JWT_CLIENT_ASSERTION_NO_CORRECT_ISS,
JWT_CLIENT_ASSERTION_NO_CORRECT_JTI,
JWT_CLIENT_ASSERTION_NO_CORRECT_SUB,
JWT_CLIENT_ASSERTION_NO_EXP,
JWT_CLIENT_ASSERTION_NO_IAT,
JWT_CLIENT_ASSERTION_NO_ISS,
JWT_CLIENT_ASSERTION_NO_JTI,
JWT_CLIENT_ASSERTION_NO_SUB,
TOKEN_AUTHN_CODE_REQUEST,
TOKEN_AUTHN_CODE_REQUEST_NO_CLIENT_ASSERTION,
TOKEN_AUTHN_CODE_REQUEST_NO_CLIENT_ASSERTION_TYPE,
TOKEN_AUTHN_CODE_REQUEST_NO_CLIENT_ID,
TOKEN_AUTHN_CODE_REQUEST_NO_CODE,
TOKEN_AUTHN_CODE_REQUEST_NO_CODE_VERIFY,
TOKEN_AUTHN_CODE_REQUEST_NO_CORRECT_CLIENT_ASSERTION,
TOKEN_AUTHN_CODE_REQUEST_NO_CORRECT_CLIENT_ASSERTION_TYPE,
TOKEN_AUTHN_CODE_REQUEST_NO_CORRECT_GRANT_TYPE,
TOKEN_AUTHN_CODE_REQUEST_NO_GRANT_TYPE,
TOKEN_REFRESH_REQUEST,
TOKEN_REFRESH_REQUEST_NO_CORRECT_GRANT_TYPE,
TOKEN_REFRESH_REQUEST_NO_GRANT_TYPE,
)
logger = logging.getLogger(__name__)
class TokenRequestTest(TestCase):
def test_validate_request(self):
TokenAuthnCodeRequest(**TOKEN_AUTHN_CODE_REQUEST)
def test_validate_request_no_client(self):
with self.assertRaises(ValidationError):
TokenAuthnCodeRequest(**TOKEN_AUTHN_CODE_REQUEST_NO_CLIENT_ID)
def test_validate_request_no_client_assertion(self):
with self.assertRaises(ValidationError):
TokenAuthnCodeRequest(**TOKEN_AUTHN_CODE_REQUEST_NO_CLIENT_ASSERTION)
def test_validate_request_no_correct_client_assertion(self):
with self.assertRaises(ValidationError):
TokenAuthnCodeRequest(
**TOKEN_AUTHN_CODE_REQUEST_NO_CORRECT_CLIENT_ASSERTION
)
def test_validate_request_no_client_assertion_type(self):
with self.assertRaises(ValidationError):
TokenAuthnCodeRequest(**TOKEN_AUTHN_CODE_REQUEST_NO_CLIENT_ASSERTION_TYPE)
def test_validate_request_no_correct_client_assertion_type(self):
with self.assertRaises(ValidationError):
TokenAuthnCodeRequest(
**TOKEN_AUTHN_CODE_REQUEST_NO_CORRECT_CLIENT_ASSERTION_TYPE
)
def test_validate_request_no_code(self):
with self.assertRaises(ValidationError):
TokenAuthnCodeRequest(**TOKEN_AUTHN_CODE_REQUEST_NO_CODE)
def test_validate_request_no_code_verify(self):
with self.assertRaises(ValidationError):
TokenAuthnCodeRequest(**TOKEN_AUTHN_CODE_REQUEST_NO_CODE_VERIFY)
def test_validate_request_no_grant_type(self):
with self.assertRaises(ValidationError):
TokenAuthnCodeRequest(**TOKEN_AUTHN_CODE_REQUEST_NO_GRANT_TYPE)
def test_validate_request_no_correct_grant_type(self):
with self.assertRaises(ValidationError):
TokenAuthnCodeRequest(**TOKEN_AUTHN_CODE_REQUEST_NO_CORRECT_GRANT_TYPE)
def test_validate_refresh_request(self):
TokenRefreshRequest(**TOKEN_REFRESH_REQUEST)
def test_validate_refresh_request_no_grant_type(self):
with self.assertRaises(ValidationError):
TokenRefreshRequest(**TOKEN_REFRESH_REQUEST_NO_GRANT_TYPE)
def test_validate_refresh_request_no_correct_grant_type(self):
with self.assertRaises(ValidationError):
TokenRefreshRequest(**TOKEN_REFRESH_REQUEST_NO_CORRECT_GRANT_TYPE)
def test_validate_jwt(self):
JwtStructure(**JWT_CLIENT_ASSERTION)
def test_validate_jwt_no_iss(self):
with self.assertRaises(ValidationError):
JwtStructure(**JWT_CLIENT_ASSERTION_NO_ISS)
def test_validate_jwt_no_correct_iss(self):
with self.assertRaises(ValidationError):
JwtStructure(**JWT_CLIENT_ASSERTION_NO_CORRECT_ISS)
def test_validate_jwt_no_sub(self):
with self.assertRaises(ValidationError):
JwtStructure(**JWT_CLIENT_ASSERTION_NO_SUB)
def test_validate_jwt_no_correct_sub(self):
with self.assertRaises(ValidationError):
JwtStructure(**JWT_CLIENT_ASSERTION_NO_CORRECT_SUB)
def test_validate_jwt_no_iat(self):
with self.assertRaises(ValidationError):
JwtStructure(**JWT_CLIENT_ASSERTION_NO_IAT)
def test_validate_jwt_no_correct_iat(self):
with self.assertRaises(ValidationError):
JwtStructure(**JWT_CLIENT_ASSERTION_NO_CORRECT_IAT)
def test_validate_jwt_no_exp(self):
with self.assertRaises(ValidationError):
JwtStructure(**JWT_CLIENT_ASSERTION_NO_EXP)
def test_validate_jwt_no_correct_exp(self):
with self.assertRaises(ValidationError):
JwtStructure(**JWT_CLIENT_ASSERTION_NO_CORRECT_EXP)
def test_validate_jwt_no_jti(self):
with self.assertRaises(ValidationError):
JwtStructure(**JWT_CLIENT_ASSERTION_NO_JTI)
def test_validate_jwt_no_correct_jti(self):
with self.assertRaises(ValidationError):
JwtStructure(**JWT_CLIENT_ASSERTION_NO_CORRECT_JTI)
def test_validate_jwt_no_aud(self):
with self.assertRaises(ValidationError):
JwtStructure(**JWT_CLIENT_ASSERTION_NO_AUD)
def test_validate_jwt_no_correct_aud(self):
with self.assertRaises(ValidationError):
JwtStructure(**JWT_CLIENT_ASSERTION_NO_CORRECT_AUD)
@@ -0,0 +1,11 @@
from django.test import TestCase
from spid_cie_oidc.provider.processors import spidCode
class ProcessorsTest(TestCase):
def test_processors(self):
processed = "9893261da4a1fec47a19b2cc4237d82f3eb70ddafdaad51bb61138b5126e72644c3189db53f9303cdc85cb84438caf9c07431944894b5742a1d33d111abf88c8"
res = spidCode({"username" : "testusername"}, {})
self.assertEqual(res, processed)
@@ -0,0 +1,77 @@
import logging
from django.test import TestCase
from pydantic import ValidationError
from spid_cie_oidc.provider.tests.token_response_settings import (
TOKEN_ERROR_RESPONSE,
TOKEN_ERROR_RESPONSE_NO_CORRECT_ERROR,
TOKEN_ERROR_RESPONSE_NO_CORRECT_ERROR_DESCRIPTION,
TOKEN_ERROR_RESPONSE_NO_ERROR,
TOKEN_ERROR_RESPONSE_NO_ERROR_DESCRIPTION,
TOKEN_REFRESH_RESPONSE,
TOKEN_REFRESH_RESPONSE_NO_CORRECT_REFRESH_TOKEN,
TOKEN_REFRESH_RESPONSE_NO_REFRESH_TOKEN,
TOKEN_RESPONSE,
TOKEN_RESPONSE_NO_ACCESS_TOKEN,
TOKEN_RESPONSE_NO_CORRECT_ACCESS_TOKEN,
TOKEN_RESPONSE_NO_CORRECT_TOKEN_TYPE,
TOKEN_RESPONSE_NO_TOKEN_TYPE,
)
from spid_cie_oidc.provider.schemas.token_response import (
TokenErrorResponse,
TokenRefreshResponse,
TokenResponse,
)
logger = logging.getLogger(__name__)
class TokenResponseTest(TestCase):
def test_validate_token_response(self):
TokenResponse(**TOKEN_RESPONSE)
def test_validate_token_response(self):
TokenRefreshResponse(**TOKEN_REFRESH_RESPONSE)
def test_validate_token_response_no_access_token(self):
with self.assertRaises(ValidationError):
TokenResponse(**TOKEN_RESPONSE_NO_ACCESS_TOKEN)
def test_validate_token_response_no_correct_access_token(self):
with self.assertRaises(ValidationError):
TokenResponse(**TOKEN_RESPONSE_NO_CORRECT_ACCESS_TOKEN)
def test_validate_token_response_no_token_type(self):
with self.assertRaises(ValidationError):
TokenResponse(**TOKEN_RESPONSE_NO_TOKEN_TYPE)
def test_validate_token_response_no_correct_token_type(self):
with self.assertRaises(ValidationError):
TokenResponse(**TOKEN_RESPONSE_NO_CORRECT_TOKEN_TYPE)
def test_validate_token_refresh_response_no_refresh_token(self):
with self.assertRaises(ValidationError):
TokenRefreshResponse(**TOKEN_REFRESH_RESPONSE_NO_REFRESH_TOKEN)
def test_validate_token_refresh_response_no_correct_refresh_token(self):
with self.assertRaises(ValidationError):
TokenRefreshResponse(**TOKEN_REFRESH_RESPONSE_NO_CORRECT_REFRESH_TOKEN)
def test_validate_token_error_response(self):
TokenErrorResponse(**TOKEN_ERROR_RESPONSE)
def test_validate_token_error_no_error(self):
with self.assertRaises(ValidationError):
TokenErrorResponse(**TOKEN_ERROR_RESPONSE_NO_ERROR)
def test_validate_token_error_no_correct_error(self):
with self.assertRaises(ValidationError):
TokenErrorResponse(**TOKEN_ERROR_RESPONSE_NO_CORRECT_ERROR)
def test_validate_token_error_no_error_description(self):
with self.assertRaises(ValidationError):
TokenErrorResponse(**TOKEN_ERROR_RESPONSE_NO_ERROR_DESCRIPTION)
def test_validate_token_error_no_correct_error_description(self):
with self.assertRaises(ValidationError):
TokenErrorResponse(**TOKEN_ERROR_RESPONSE_NO_CORRECT_ERROR_DESCRIPTION)
@@ -0,0 +1,89 @@
from unittest.mock import patch
from django.core.management import call_command
from django.test import TestCase, override_settings
from spid_cie_oidc.authority.tests.settings import (
RP_CONF_AS_JSON,
RP_METADATA_JWK1
)
from spid_cie_oidc.entity.jwtse import create_jws
from spid_cie_oidc.entity.models import (
FetchedEntityStatement,
TrustChain
)
from spid_cie_oidc.entity.tests.settings import (
TA_JWK_PRIVATE,
TA_SUB,
ta_conf_data_as_json
)
from spid_cie_oidc.entity.utils import (
datetime_from_timestamp,
exp_from_now,
iat_now
)
EXP = datetime_from_timestamp(exp_from_now(33))
NOW = datetime_from_timestamp(iat_now())
def create_entity_config():
JWS_RP = create_jws(RP_CONF_AS_JSON, RP_METADATA_JWK1, typ="entity-statement+jwt")
JWS_TA = create_jws(ta_conf_data_as_json, TA_JWK_PRIVATE, typ="entity-statement+jwt")
return [JWS_RP, JWS_TA]
def create_tc():
ta_fes = FetchedEntityStatement.objects.create(
sub=TA_SUB,
iss=TA_SUB,
exp=EXP,
iat=NOW
)
return TrustChain.objects.create(
sub=RP_CONF_AS_JSON["sub"],
exp=EXP,
jwks = [],
metadata=RP_CONF_AS_JSON["metadata"],
status="valid",
trust_anchor=ta_fes,
is_active=True,
)
class FetchRPTest(TestCase):
def setUp(self):
self.ta_fes = FetchedEntityStatement.objects.create(
sub=TA_SUB,
iss=TA_SUB,
exp=datetime_from_timestamp(exp_from_now(33)),
iat=datetime_from_timestamp(iat_now()),
)
def exec(self, cmd_name:str, *args, **kwargs):
call_command(
cmd_name,
*args,
**kwargs,
)
@override_settings(OIDCFED_IDENTITY_PROVIDERS = {"spid":{"http://127.0.0.1:8000/oidc/op/" :"http://testserver/"}, "cie":{}})
@override_settings(OIDCFED_TRUST_ANCHOR = [])
def test_fetch_rp(self):
self.patcher = patch(
"spid_cie_oidc.entity.statements.get_entity_configurations",
return_value = create_entity_config()
)
self.patcher.start()
self.patcher = patch(
"spid_cie_oidc.entity.statements.get_http_url",
return_value = ['["http://rp-test.it/oidc/rp/"]']
)
self.patcher.start()
self.patcher = patch(
"spid_cie_oidc.entity.trust_chain_operations.get_or_create_trust_chain",
return_value = create_tc()
)
self.patcher.start()
self.exec('fetch_openid_relying_parties', '--from', 'url')
self.patcher.stop()
@@ -0,0 +1,53 @@
from django.test import TestCase
from pydantic import ValidationError
from spid_cie_oidc.provider.tests.introspection_request_settings import (
INTROSPECTION_REQUEST,
INTROSPECTION_REQUEST_NO_CLIENT_ASSERTION,
INTROSPECTION_REQUEST_NO_CLIENT_ASSERTION_TYPE,
INTROSPECTION_REQUEST_NO_CLIENT_ID,
INTROSPECTION_REQUEST_NO_CORRECT_CLIENT_ASSERTION,
INTROSPECTION_REQUEST_NO_CORRECT_CLIENT_ASSERTION_TYPE,
INTROSPECTION_REQUEST_NO_CORRECT_CLIENT_ID,
INTROSPECTION_REQUEST_NO_CORRECT_TOKEN,
INTROSPECTION_REQUEST_NO_TOKEN,
)
from spid_cie_oidc.provider.schemas.introspection_request import IntrospectionRequest
class IntrospectionRequestTest(TestCase):
def test_validate_introspection_request(self):
IntrospectionRequest(**INTROSPECTION_REQUEST)
def test_validate_introspection_request_no_client_assertion(self):
with self.assertRaises(ValidationError):
IntrospectionRequest(**INTROSPECTION_REQUEST_NO_CLIENT_ASSERTION)
def test_validate_introspection_request_no_correct_client_assertion(self):
with self.assertRaises(ValidationError):
IntrospectionRequest(**INTROSPECTION_REQUEST_NO_CORRECT_CLIENT_ASSERTION)
def test_validate_introspection_request_no_client_assertion_type(self):
with self.assertRaises(ValidationError):
IntrospectionRequest(**INTROSPECTION_REQUEST_NO_CLIENT_ASSERTION_TYPE)
def test_validate_introspection_request_no_correct_client_assertion_type(self):
with self.assertRaises(ValidationError):
IntrospectionRequest(
**INTROSPECTION_REQUEST_NO_CORRECT_CLIENT_ASSERTION_TYPE
)
def test_validate_introspection_request_no_client_id(self):
with self.assertRaises(ValidationError):
IntrospectionRequest(**INTROSPECTION_REQUEST_NO_CLIENT_ID)
def test_validate_introspection_request_no_correct_client_id(self):
with self.assertRaises(ValidationError):
IntrospectionRequest(**INTROSPECTION_REQUEST_NO_CORRECT_CLIENT_ID)
def test_validate_introspection_request_no_token(self):
with self.assertRaises(ValidationError):
IntrospectionRequest(**INTROSPECTION_REQUEST_NO_TOKEN)
def test_validate_introspection_request_no_correct_token(self):
with self.assertRaises(ValidationError):
IntrospectionRequest(**INTROSPECTION_REQUEST_NO_CORRECT_TOKEN)
@@ -0,0 +1,68 @@
from django.test import TestCase
from pydantic import ValidationError
from spid_cie_oidc.provider.tests.introspection_response_settings import (
INTROSPECTION_ERROR_RESPONSE,
INTROSPECTION_ERROR_RESPONSE_CIE_NO_CORRECT_ERROR,
INTROSPECTION_ERROR_RESPONSE_CIE_NO_ERROR,
INTROSPECTION_ERROR_RESPONSE_NO_CORRECT_ERROR_DESCRIPTION,
INTROSPECTION_ERROR_RESPONSE_NO_ERROR_DESCRIPTION,
INTROSPECTION_ERROR_RESPONSE_SPID_NO_CORRECT_ERROR,
INTROSPECTION_ERROR_RESPONSE_SPID_NO_ERROR,
INTROSPECTION_RESPONSE,
INTROSPECTION_RESPONSE_NO_ACTIVE,
INTROSPECTION_RESPONSE_NO_CORRECT_ACTIVE,
)
from spid_cie_oidc.provider.schemas.introspection_response import (
IntrospectionErrorResponse,
IntrospectionErrorResponseCie,
IntrospectionErrorResponseSpid,
IntrospectionResponse,
)
class IntrospectionResponseTest(TestCase):
def test_validate_introspection_response(self):
IntrospectionResponse(**INTROSPECTION_RESPONSE)
def test_validate_introspection_response_no_active(self):
with self.assertRaises(ValidationError):
IntrospectionResponse(**INTROSPECTION_RESPONSE_NO_ACTIVE)
def test_validate_introspection_response_no_correct_active(self):
with self.assertRaises(ValidationError):
IntrospectionResponse(**INTROSPECTION_RESPONSE_NO_CORRECT_ACTIVE)
def test_validate_introspection_error_response(self):
IntrospectionErrorResponse(**INTROSPECTION_ERROR_RESPONSE)
def test_validate_introspection_response_spid_no_error(self):
with self.assertRaises(ValidationError):
IntrospectionErrorResponseSpid(**INTROSPECTION_ERROR_RESPONSE_SPID_NO_ERROR)
def test_validate_introspection_response_spid_no_correct_error(self):
with self.assertRaises(ValidationError):
IntrospectionErrorResponseSpid(
**INTROSPECTION_ERROR_RESPONSE_SPID_NO_CORRECT_ERROR
)
def test_validate_introspection_response_cie_no_error(self):
with self.assertRaises(ValidationError):
IntrospectionErrorResponseCie(**INTROSPECTION_ERROR_RESPONSE_CIE_NO_ERROR)
def test_validate_introspection_response_cie_no_correct_error(self):
with self.assertRaises(ValidationError):
IntrospectionErrorResponseCie(
**INTROSPECTION_ERROR_RESPONSE_CIE_NO_CORRECT_ERROR
)
def test_validate_introspection_response_no_error_description(self):
with self.assertRaises(ValidationError):
IntrospectionErrorResponse(
**INTROSPECTION_ERROR_RESPONSE_NO_ERROR_DESCRIPTION
)
def test_validate_introspection_response_no_correct_error_description(self):
with self.assertRaises(ValidationError):
IntrospectionErrorResponse(
**INTROSPECTION_ERROR_RESPONSE_NO_CORRECT_ERROR_DESCRIPTION
)
@@ -0,0 +1,145 @@
from copy import deepcopy
from django.test import Client, TestCase
from django.urls import reverse
from django.utils import timezone
from spid_cie_oidc.accounts.models import User
from spid_cie_oidc.authority.tests.settings import (
RP_METADATA,
RP_METADATA_JWK1,
rp_conf
)
from spid_cie_oidc.entity.jwtse import create_jws
from spid_cie_oidc.entity.models import (
FederationEntityConfiguration,
FetchedEntityStatement,
TrustChain
)
from spid_cie_oidc.entity.tests.settings import TA_SUB
from spid_cie_oidc.entity.utils import (
datetime_from_timestamp,
exp_from_now,
iat_now
)
from spid_cie_oidc.provider.models import IssuedToken, OidcSession
from spid_cie_oidc.provider.tests.settings import op_conf, op_conf_priv_jwk
from spid_cie_oidc.relying_party.utils import get_pkce
RP_SUB = rp_conf["sub"]
RP_CLIENT_ID = rp_conf["metadata"]["openid_relying_party"]["client_id"]
PKCE = get_pkce()
class RefreshTokenTest(TestCase):
def setUp(self):
self.op_local_conf = deepcopy(op_conf)
FederationEntityConfiguration.objects.create(**self.op_local_conf)
self.ta_fes = FetchedEntityStatement.objects.create(
sub=TA_SUB,
iss=TA_SUB,
exp=datetime_from_timestamp(exp_from_now(33)),
iat=datetime_from_timestamp(iat_now()),
)
self.trust_chain = TrustChain.objects.create(
sub=RP_SUB,
exp=datetime_from_timestamp(exp_from_now(33)),
jwks = [],
metadata=RP_METADATA,
status="valid",
trust_anchor=self.ta_fes,
is_active=True,
)
self.jwt_auds = [op_conf["sub"], "http://testserver/oidc/op/", "http://testserver/oidc/op/token"]
CLIENT_ASSERTION = {
"iss": RP_SUB,
"sub": RP_SUB,
"aud": self.jwt_auds,
"exp": exp_from_now(),
"iat": iat_now(),
"jti": "jti",
}
self.ca_jws = create_jws(CLIENT_ASSERTION, RP_METADATA_JWK1)
self.refresh_token = {
"iss": self.op_local_conf["sub"],
"sub": RP_SUB,
"exp": exp_from_now(),
"iat": iat_now(),
"aud": self.jwt_auds,
"client_id": RP_CLIENT_ID,
"scope": "openid",
}
session = OidcSession.objects.create(
user=User.objects.create(username = "username"),
user_uid="",
nonce="",
authz_request={"scope": "openid", "nonce": "123", "code_challenge": PKCE["code_challenge"]},
client_id="",
auth_code="code",
)
IssuedToken.objects.create(
access_token = create_jws(self.refresh_token, op_conf_priv_jwk, typ="at-jwt"),
refresh_token = create_jws(self.refresh_token, op_conf_priv_jwk),
session = session,
expires = timezone.localtime()
)
def test_token_endpoint(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",
grant_type="authorization_code",
code="code",
code_verifier = PKCE["code_verifier"]
)
res = client.post(url, request)
self.assertTrue(res.status_code == 200)
self.assertTrue(res.json().get("access_token"))
def test_token_endpoint_get(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",
grant_type="authorization_code",
code = "code",
code_verifier = "code_verifier"
)
res = client.get(url, request)
self.assertTrue(res.status_code == 400)
def test_token_endpoint_no_client_id(self):
client = Client()
url = reverse("oidc_provider_token_endpoint")
request = dict(
client_assertion = self.ca_jws,
client_assertion_type = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
grant_type="authorization_code",
code = "code",
code_verifier = "code_verifier"
)
res = client.post(url, request)
self.assertTrue(res.status_code == 400)
self.assertTrue("invalid_request" == res.json().get("error"))
def test_token_endpoint_no_session(self):
OidcSession.objects.all().delete()
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",
grant_type="authorization_code",
code = "code",
code_verifier = "code_verifier"
)
res = client.post(url, request)
self.assertTrue(res.status_code == 400)
@@ -0,0 +1,110 @@
from copy import deepcopy
from django.test import Client, TestCase
from django.urls import reverse
from spid_cie_oidc.accounts.models import User
from spid_cie_oidc.authority.tests.settings import (
RP_CONF_AS_JSON,
RP_METADATA_JWK1,
rp_conf
)
from spid_cie_oidc.entity.jwtse import create_jws
from spid_cie_oidc.entity.models import (
FederationEntityConfiguration,
FetchedEntityStatement,
TrustChain
)
from spid_cie_oidc.entity.tests.settings import TA_SUB
from spid_cie_oidc.entity.utils import (
datetime_from_timestamp,
exp_from_now,
iat_now
)
from spid_cie_oidc.provider.models import IssuedToken, OidcSession
from spid_cie_oidc.provider.tests.settings import op_conf, op_conf_priv_jwk
RP_SUB = rp_conf["sub"]
RP_CLIENT_ID = rp_conf["metadata"]["openid_relying_party"]["client_id"]
class RevocationEndponitTest(TestCase):
def setUp(self):
ta_fes = FetchedEntityStatement.objects.create(
sub=TA_SUB,
iss=TA_SUB,
exp=datetime_from_timestamp(exp_from_now(33)),
iat=datetime_from_timestamp(iat_now()),
)
self.op_local_conf = deepcopy(op_conf)
FederationEntityConfiguration.objects.create(**self.op_local_conf)
self.jwt_auds = [op_conf["sub"], "http://testserver/oidc/op/", "http://testserver/oidc/op/revocation"]
CLIENT_ASSERTION = {
"iss": RP_SUB,
"sub": RP_SUB,
"aud": self.jwt_auds,
"exp": exp_from_now(),
"iat": iat_now(),
"jti": "jti",
}
self.ca_jws = create_jws(CLIENT_ASSERTION, RP_METADATA_JWK1)
access_token = {
"iss": self.op_local_conf["sub"],
"sub": RP_SUB,
"aud": self.jwt_auds,
"client_id": RP_CLIENT_ID,
"scope": "openid",
}
self.at_jws = create_jws(access_token, op_conf_priv_jwk)
self.request = dict(
client_id = RP_CLIENT_ID,
client_assertion = self.ca_jws,
client_assertion_type = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
token = self.at_jws,
)
session = OidcSession.objects.create(
user=User.objects.create(username = "username"),
user_uid="",
nonce="",
authz_request={"scope": "openid"},
client_id=rp_conf["sub"],
)
iss_token_data = dict(
session=session,
access_token= self.at_jws,
id_token= "id_token",
refresh_token= "refresh_token",
expires=datetime_from_timestamp(exp_from_now())
)
IssuedToken.objects.create(**iss_token_data)
TrustChain.objects.create(
sub=RP_CONF_AS_JSON["sub"],
exp=datetime_from_timestamp(exp_from_now(33)),
jwks = [],
metadata=RP_CONF_AS_JSON["metadata"],
status="valid",
trust_anchor=ta_fes,
is_active=True,
)
def test_revocation_endpoint(self):
client = Client()
url = reverse("oidc_provider_end_session_endpoint")
res = client.post(url, self.request)
self.assertTrue(res.status_code == 200)
def test_revocation_endpoint_no_correct_client_assert(self):
client = Client()
request = deepcopy(self.request)
request["client_assertion"] = "q.q.q"
url = reverse("oidc_provider_end_session_endpoint")
res = client.post(url, request)
self.assertTrue(res.status_code == 400)
def test_revocation_endpoint_no_issued_token(self):
client = Client()
IssuedToken.objects.all().delete()
url = reverse("oidc_provider_end_session_endpoint")
res = client.post(url, self.request)
self.assertTrue(res.status_code == 400)
@@ -0,0 +1,62 @@
from copy import deepcopy
from django.test import TestCase
from pydantic import ValidationError
from spid_cie_oidc.provider.tests.revocation_request_settings import (
REVOCATION_REQUEST,
REVOCATION_REQUEST_NO_CLIENT_ASSERTION,
REVOCATION_REQUEST_NO_CLIENT_ASSERTION_TYPE,
REVOCATION_REQUEST_NO_CLIENT_ID,
REVOCATION_REQUEST_NO_CORRECT_CLIENT_ASSERTION,
REVOCATION_REQUEST_NO_CORRECT_CLIENT_ASSERTION_TYPE,
REVOCATION_REQUEST_NO_CORRECT_CLIENT_ID,
REVOCATION_REQUEST_NO_CORRECT_TOKEN,
REVOCATION_REQUEST_NO_TOKEN,
)
from spid_cie_oidc.entity.models import (
FederationEntityConfiguration
)
from spid_cie_oidc.provider.schemas.revocation_request import RevocationRequest
from spid_cie_oidc.provider.tests.settings import (
op_conf
)
class RevocationRequestTest(TestCase):
def setUp(self):
self.op_local_conf = deepcopy(op_conf)
FederationEntityConfiguration.objects.create(**self.op_local_conf)
def test_validate_revocation_request(self):
RevocationRequest(**REVOCATION_REQUEST)
def test_validate_revocation_request_no_client_assertion(self):
with self.assertRaises(ValidationError):
RevocationRequest(**REVOCATION_REQUEST_NO_CLIENT_ASSERTION)
def test_validate_revocation_request_no_correct_client_assertion(self):
with self.assertRaises(ValidationError):
RevocationRequest(**REVOCATION_REQUEST_NO_CORRECT_CLIENT_ASSERTION)
def test_validate_revocation_request_no_client_assertion_type(self):
with self.assertRaises(ValidationError):
RevocationRequest(**REVOCATION_REQUEST_NO_CLIENT_ASSERTION_TYPE)
def test_validate_revocation_request_no_correct_client_assertion_type(self):
with self.assertRaises(ValidationError):
RevocationRequest(**REVOCATION_REQUEST_NO_CORRECT_CLIENT_ASSERTION_TYPE)
def test_validate_revocation_request_no_client_id(self):
with self.assertRaises(ValidationError):
RevocationRequest(**REVOCATION_REQUEST_NO_CLIENT_ID)
def test_validate_revocation_request_no_correct_client_id(self):
with self.assertRaises(ValidationError):
RevocationRequest(**REVOCATION_REQUEST_NO_CORRECT_CLIENT_ID)
def test_validate_revocation_request_no_token(self):
with self.assertRaises(ValidationError):
RevocationRequest(**REVOCATION_REQUEST_NO_TOKEN)
def test_validate_revocation_request_no_correct_token(self):
with self.assertRaises(ValidationError):
RevocationRequest(**REVOCATION_REQUEST_NO_CORRECT_TOKEN)
@@ -0,0 +1,18 @@
from django.test import Client, TestCase
from django.urls import reverse
from spid_cie_oidc.authority.tests.settings import rp_conf
class NoConsentTest(TestCase):
def setUp(self):
pass
def test_no_consent(self):
client = Client()
url = reverse("oidc_provider_not_consent")
redirect_uri = rp_conf["metadata"]["openid_relying_party"]["redirect_uris"][0]
res = client.get(url + "?redirect_uri=" + redirect_uri)
self.assertTrue(res.status_code == 302)
self.assertTrue("Authentication+request+rejected+by+user" in res.url)
@@ -0,0 +1,35 @@
from django.test import TestCase
from pydantic import ValidationError
from spid_cie_oidc.provider.tests.revocation_response_settings import (
REVOCATION_RESPONSE_CIE,
REVOCATION_RESPONSE_CIE_NO_CORRECT_ERROR,
REVOCATION_RESPONSE_CIE_NO_CORRECT_ERROR_DESCRIPTION,
REVOCATION_RESPONSE_CIE_NO_ERROR,
REVOCATION_RESPONSE_CIE_NO_ERROR_DESCRIPTION,
)
from spid_cie_oidc.provider.schemas.revocation_response import (
RevocationErrorResponse,
)
class RevocationResponseTest(TestCase):
def test_validate_revocation_response(self):
RevocationErrorResponse(**REVOCATION_RESPONSE_CIE)
def test_validate_revocation_response_no_error(self):
with self.assertRaises(ValidationError):
RevocationErrorResponse(**REVOCATION_RESPONSE_CIE_NO_ERROR)
def test_validate_revocation_response_no_correct_error(self):
with self.assertRaises(ValidationError):
RevocationErrorResponse(**REVOCATION_RESPONSE_CIE_NO_CORRECT_ERROR)
def test_validate_revocation_response_no_error_description(self):
with self.assertRaises(ValidationError):
RevocationErrorResponse(**REVOCATION_RESPONSE_CIE_NO_ERROR_DESCRIPTION)
def test_validate_revocation_response_no_correct_error_description(self):
with self.assertRaises(ValidationError):
RevocationErrorResponse(
**REVOCATION_RESPONSE_CIE_NO_CORRECT_ERROR_DESCRIPTION
)
@@ -0,0 +1,70 @@
from django.contrib.auth import get_user_model
from django.test import Client, TestCase
from django.urls import reverse
from spid_cie_oidc.authority.tests.settings import rp_conf
from spid_cie_oidc.provider.models import OidcSession
class UserAccessHistoryTest(TestCase):
def setUp(self):
self.user = get_user_model().objects.create(
username="test",
first_name="test",
last_name="test",
email="[email protected]",
is_staff=True
)
self.user.set_password("test")
self.user.save()
OidcSession.objects.create(
user=self.user,
user_uid="uid",
nonce="",
authz_request={
"scope": "openid",
"nonce": "123",
"acr_values": ["https://www.spid.gov.it/SpidL2"],
"redirect_uri": rp_conf["metadata"]["openid_relying_party"]["redirect_uris"][0],
"state": "state",
},
client_id="",
auth_code="auth_code",
)
OidcSession.objects.create(
user=self.user,
user_uid="uid",
nonce="1234",
authz_request={
"scope": "openid",
"nonce": "1234",
"acr_values": ["https://www.spid.gov.it/SpidL2"],
"redirect_uri": rp_conf["metadata"]["openid_relying_party"]["redirect_uris"][0],
"state": "state",
},
client_id="",
auth_code="code",
)
def test_user_access_history(self):
client = Client()
client.login(username="test", password="test")
session = client.session
session.update({"oidc": {"auth_code": "code"}, "user_uid": "uid"})
session.save()
url = reverse("oidc_provider_access_history")
res = client.get(url)
self.assertTrue(res.status_code == 200)
self.assertTrue("auth_code=auth_code" in res.content.decode())
def test_user_access_history_revoke(self):
client = Client()
client.login(username="test", password="test")
session = client.session
session.update({"oidc": {"auth_code": "code"}, "user_uid": "uid"})
session.save()
url = reverse("oidc_provider_revoke_session")
res = client.get(url, {"auth_code": "auth_code"})
self.assertTrue(res.status_code == 302)
url_history = reverse("oidc_provider_access_history")
self.assertTrue(url_history in res.url)
@@ -0,0 +1,36 @@
from django.test import TestCase
from spid_cie_oidc.provider.models import OidcSession
from spid_cie_oidc.provider.views.__init__ import OpBase
class InitTest(TestCase):
def setUp(self):
self.client_assertion = 'eyJhbGciOiJSUzI1NiIsImtpZCI6IjJIbm9GUzNZbkM5dGppQ2FpdmhXTFZVSjNBeHdHR3pfOTh1UkZhcU1FRXMifQ.eyJpc3MiOiJodHRwOi8vMTI3LjAuMC4xOjgwMDAvb2lkYy9ycC8iLCJzdWIiOiJodHRwOi8vMTI3LjAuMC4xOjgwMDAvb2lkYy9ycC8iLCJhdWQiOlsiaHR0cDovLzEyNy4wLjAuMTo4MDAwL29pZGMvb3AvdG9rZW4vIl0sImlhdCI6MTY0ODQ5NTc1NywiZXhwIjoxNjQ4NDk3NzM3LCJqdGkiOiI0OWE2OGQyMS03NTE1LTRmNDMtODZhZC1hMDNhMWNmNDFmNTgifQ.EaWmmuDhoa8jt_go4zrY5AhTGnljIS1zNwIF-f9eBidAiWPYaKwmXRsRoXrAeybLcJ5E8-7TO1S8jZiCxcElQPdRRvuP9ZsgNhfEqDhZtabkwGBFt4gpQZnFsgGDMAi-v4sTM55VsnIJIMrHPNIckZfL-YhD-FSCtDsqrCkCnucXR58Kfp_SEx3hJvrU-2vcOeNXJBTqs3pHl9jws9GJIf6bZd7vQqTMolCC4zBzUp7yT3OXqMt9uCUhLZzLtpTRW0_-u-KW4h44eHOdEf6ePqiFhjflF9_T6cM-OBqzaK0eVvg6RcasvF3IyxdG-ME5crapAibeePqg_Hy__Q5idQ'
self.session = OidcSession.objects.create(
user_uid="",
nonce="",
authz_request={"scope": "offline_access", "prompt": "consent", "nonce": "123", "acr_values":["https://www.spid.gov.it/SpidL1"]},
client_id="",
auth_code="code",
)
def test_validate_authz_request_object(self):
with self.assertRaises(Exception):
OpBase.validate_authz_request_object(self,{})
def test_check_client_assertion(self):
with self.assertRaises(Exception):
OpBase.check_client_assertion(self, client_id = "", client_assertion = self.client_assertion)
def test_get_refresh_token(self):
result = OpBase.get_refresh_token(
self,
iss_sub = "sub",
sub = "sub",
authz = self.session,
jwt_at = "jwt_at",
commons= {}
)
self.assertEqual(result["sub"], "sub")
@@ -0,0 +1,107 @@
from copy import deepcopy
from spid_cie_oidc.entity.utils import exp_from_now, iat_now
TOKEN_REQUEST = {
"client_id": "https://rp.cie.it",
"client_assertion": "head.payload.verifysignature",
"client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
}
TOKEN_AUTHN_CODE_REQUEST = deepcopy(TOKEN_REQUEST)
TOKEN_AUTHN_CODE_REQUEST["code"] = "usDwMnEzJPpG5oaV8x3j&"
TOKEN_AUTHN_CODE_REQUEST["code_verifier"] = "9g8S40MozM3NSqjHnhi7OnsE38jklFv2&"
TOKEN_AUTHN_CODE_REQUEST["grant_type"] = "authorization_code"
TOKEN_AUTHN_CODE_REQUEST_NO_CLIENT_ID = deepcopy(TOKEN_AUTHN_CODE_REQUEST)
TOKEN_AUTHN_CODE_REQUEST_NO_CLIENT_ID.pop("client_id")
TOKEN_AUTHN_CODE_REQUEST_NO_CLIENT_ASSERTION = deepcopy(TOKEN_AUTHN_CODE_REQUEST)
TOKEN_AUTHN_CODE_REQUEST_NO_CLIENT_ASSERTION.pop("client_assertion")
TOKEN_AUTHN_CODE_REQUEST_NO_CORRECT_CLIENT_ASSERTION = deepcopy(
TOKEN_AUTHN_CODE_REQUEST
)
TOKEN_AUTHN_CODE_REQUEST_NO_CORRECT_CLIENT_ASSERTION["client_assertion"] = "head..sign"
TOKEN_AUTHN_CODE_REQUEST_NO_CLIENT_ASSERTION_TYPE = deepcopy(TOKEN_AUTHN_CODE_REQUEST)
TOKEN_AUTHN_CODE_REQUEST_NO_CLIENT_ASSERTION_TYPE.pop("client_assertion_type")
TOKEN_AUTHN_CODE_REQUEST_NO_CORRECT_CLIENT_ASSERTION_TYPE = deepcopy(
TOKEN_AUTHN_CODE_REQUEST
)
TOKEN_AUTHN_CODE_REQUEST_NO_CORRECT_CLIENT_ASSERTION_TYPE[
"client_assertion_type"
] = ":params:oauth:client-assertion-type:"
TOKEN_AUTHN_CODE_REQUEST_NO_CODE = deepcopy(TOKEN_AUTHN_CODE_REQUEST)
TOKEN_AUTHN_CODE_REQUEST_NO_CODE.pop("code")
TOKEN_AUTHN_CODE_REQUEST_NO_CODE_VERIFY = deepcopy(TOKEN_AUTHN_CODE_REQUEST)
TOKEN_AUTHN_CODE_REQUEST_NO_CODE_VERIFY.pop("code_verifier")
TOKEN_AUTHN_CODE_REQUEST_NO_GRANT_TYPE = deepcopy(TOKEN_AUTHN_CODE_REQUEST)
TOKEN_AUTHN_CODE_REQUEST_NO_GRANT_TYPE.pop("grant_type")
TOKEN_AUTHN_CODE_REQUEST_NO_CORRECT_GRANT_TYPE = deepcopy(TOKEN_AUTHN_CODE_REQUEST)
TOKEN_AUTHN_CODE_REQUEST_NO_CORRECT_GRANT_TYPE["grant_type"] = "refresh_token"
TOKEN_REFRESH_REQUEST = deepcopy(TOKEN_REQUEST)
TOKEN_REFRESH_REQUEST["grant_type"] = "refresh_token"
TOKEN_REFRESH_REQUEST["refresh_token"] = "8xLOxBtZp8"
TOKEN_REFRESH_REQUEST_NO_GRANT_TYPE = deepcopy(TOKEN_REFRESH_REQUEST)
TOKEN_REFRESH_REQUEST_NO_GRANT_TYPE.pop("grant_type")
TOKEN_REFRESH_REQUEST_NO_CORRECT_GRANT_TYPE = deepcopy(TOKEN_REFRESH_REQUEST)
TOKEN_REFRESH_REQUEST_NO_CORRECT_GRANT_TYPE["grant_type"] = "authorization_code"
# TODO: we need factory function to get fresh now
IAT = iat_now()
EXP = exp_from_now()
JWT_CLIENT_ASSERTION = {
"iss": "https://rp.cie.it",
"sub": "https://rp.cie.it",
"iat": IAT,
"exp": EXP,
"aud": ["https://rp.spid.agid.gov.it/auth"],
"jti": "a72d5df0-2415-4c7c-a44f-3988b354040b",
}
JWT_CLIENT_ASSERTION_NO_ISS = deepcopy(JWT_CLIENT_ASSERTION)
JWT_CLIENT_ASSERTION_NO_ISS.pop("iss")
JWT_CLIENT_ASSERTION_NO_CORRECT_ISS = deepcopy(JWT_CLIENT_ASSERTION)
JWT_CLIENT_ASSERTION_NO_CORRECT_ISS["iss"] = "https://idserve.i"
JWT_CLIENT_ASSERTION_NO_SUB = deepcopy(JWT_CLIENT_ASSERTION)
JWT_CLIENT_ASSERTION_NO_SUB.pop("sub")
JWT_CLIENT_ASSERTION_NO_CORRECT_SUB = deepcopy(JWT_CLIENT_ASSERTION)
JWT_CLIENT_ASSERTION_NO_CORRECT_SUB["sub"] = "https://idserver"
JWT_CLIENT_ASSERTION_NO_IAT = deepcopy(JWT_CLIENT_ASSERTION)
JWT_CLIENT_ASSERTION_NO_IAT.pop("iat")
JWT_CLIENT_ASSERTION_NO_CORRECT_IAT = deepcopy(JWT_CLIENT_ASSERTION)
JWT_CLIENT_ASSERTION_NO_CORRECT_IAT["iat"] = str(IAT + 400)
JWT_CLIENT_ASSERTION_NO_EXP = deepcopy(JWT_CLIENT_ASSERTION)
JWT_CLIENT_ASSERTION_NO_EXP.pop("exp")
JWT_CLIENT_ASSERTION_NO_CORRECT_EXP = deepcopy(JWT_CLIENT_ASSERTION)
JWT_CLIENT_ASSERTION_NO_CORRECT_EXP["exp"] = 1000
JWT_CLIENT_ASSERTION_NO_JTI = deepcopy(JWT_CLIENT_ASSERTION)
JWT_CLIENT_ASSERTION_NO_JTI.pop("jti")
JWT_CLIENT_ASSERTION_NO_CORRECT_JTI = deepcopy(JWT_CLIENT_ASSERTION)
JWT_CLIENT_ASSERTION_NO_CORRECT_JTI["jti"] = []
JWT_CLIENT_ASSERTION_NO_AUD = deepcopy(JWT_CLIENT_ASSERTION)
JWT_CLIENT_ASSERTION_NO_AUD.pop("aud")
JWT_CLIENT_ASSERTION_NO_CORRECT_AUD = deepcopy(JWT_CLIENT_ASSERTION)
JWT_CLIENT_ASSERTION_NO_CORRECT_AUD["aud"] = "https://rp.spid.agid.gov.it/auth"
@@ -0,0 +1,47 @@
from copy import deepcopy
TOKEN_RESPONSE = {
"access_token": "dC34Pf6kdG.Gjpw5HN6c.JSKABYDGye6",
"token_type": "Bearer",
"expires_in": 1800,
"id_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY.ashajrbGFDGd",
}
TOKEN_RESPONSE_NO_ACCESS_TOKEN = deepcopy(TOKEN_RESPONSE)
TOKEN_RESPONSE_NO_ACCESS_TOKEN.pop("access_token")
TOKEN_RESPONSE_NO_CORRECT_ACCESS_TOKEN = deepcopy(TOKEN_RESPONSE)
TOKEN_RESPONSE_NO_CORRECT_ACCESS_TOKEN["access_token"] = "dC34Pf6kdG.Gjpw5HN"
TOKEN_RESPONSE_NO_TOKEN_TYPE = deepcopy(TOKEN_RESPONSE)
TOKEN_RESPONSE_NO_TOKEN_TYPE.pop("token_type")
TOKEN_RESPONSE_NO_CORRECT_TOKEN_TYPE = deepcopy(TOKEN_RESPONSE)
TOKEN_RESPONSE_NO_CORRECT_TOKEN_TYPE["token_type"] = "prova"
TOKEN_REFRESH_RESPONSE = deepcopy(TOKEN_RESPONSE)
TOKEN_REFRESH_RESPONSE["refresh_token"] = "wJ848BcyLP.hHhJB.kjHMjUGUSGKEE3"
TOKEN_REFRESH_RESPONSE_NO_REFRESH_TOKEN = deepcopy(TOKEN_REFRESH_RESPONSE)
TOKEN_REFRESH_RESPONSE_NO_REFRESH_TOKEN.pop("refresh_token")
TOKEN_REFRESH_RESPONSE_NO_CORRECT_REFRESH_TOKEN = deepcopy(TOKEN_REFRESH_RESPONSE)
TOKEN_REFRESH_RESPONSE_NO_CORRECT_REFRESH_TOKEN["refresh_token"] = "dC34Pf6kdG..Gjpw5HN"
TOKEN_ERROR_RESPONSE = {
"error": "invalid_request",
"error_description": "descrizione dell’errore",
}
TOKEN_ERROR_RESPONSE_NO_ERROR = deepcopy(TOKEN_ERROR_RESPONSE)
TOKEN_ERROR_RESPONSE_NO_ERROR.pop("error")
TOKEN_ERROR_RESPONSE_NO_CORRECT_ERROR = deepcopy(TOKEN_ERROR_RESPONSE)
TOKEN_ERROR_RESPONSE_NO_CORRECT_ERROR["error"] = ""
TOKEN_ERROR_RESPONSE_NO_ERROR_DESCRIPTION = deepcopy(TOKEN_ERROR_RESPONSE)
TOKEN_ERROR_RESPONSE_NO_ERROR_DESCRIPTION.pop("error_description")
TOKEN_ERROR_RESPONSE_NO_CORRECT_ERROR_DESCRIPTION = deepcopy(TOKEN_ERROR_RESPONSE)
TOKEN_ERROR_RESPONSE_NO_CORRECT_ERROR_DESCRIPTION["error"] = []