Skip to content

Commit

Permalink
✨ Add some types
Browse files Browse the repository at this point in the history
I was going crazy navigating all the different config dicts, so I added some types. They need further development, but they are better than nothing (I think).
  • Loading branch information
SilviaAmAm committed Mar 13, 2024
1 parent ed5a54f commit 46eda33
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 12 deletions.
26 changes: 15 additions & 11 deletions digid_eherkenning/saml2/eherkenning.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import binascii
from base64 import b64encode
from io import BytesIO
from typing import List, Literal, Union
from typing import Literal, Union
from uuid import uuid4

from django.urls import reverse
Expand All @@ -12,10 +12,12 @@
from furl.furl import furl
from lxml.builder import ElementMaker
from lxml.etree import Element, tostring
from onelogin.saml2.settings import OneLogin_Saml2_Settings

from ..choices import AssuranceLevels
from ..models import EherkenningConfiguration
from ..settings import EHERKENNING_DS_XSD
from ..types import EHerkenningConfig, EHerkenningSAMLConfig, ServiceConfig
from ..utils import validate_xml
from .base import BaseSaml2Client, get_service_description, get_service_name

Expand All @@ -36,7 +38,7 @@

def generate_dienst_catalogus_metadata(eherkenning_config=None):
eherkenning_config = eherkenning_config or EherkenningConfiguration.get_solo()
settings = eherkenning_config.as_dict()
settings: EHerkenningConfig = eherkenning_config.as_dict()
# ensure that the single language strings are output in both nl and en
for service in settings["services"]:
name = service["service_name"]
Expand Down Expand Up @@ -295,7 +297,7 @@ def create_classifiers_element(classifiers: list) -> ElementMaker:
return ESC("Classifiers", *classifiers_elements)


def create_key_descriptor(x509_certificate_content: bytes):
def create_key_descriptor(x509_certificate_content: bytes) -> ElementMaker:
certificate = load_pem_x509_certificate(x509_certificate_content)
key_name = binascii.hexlify(
certificate.fingerprint(certificate.signature_hash_algorithm)
Expand All @@ -317,7 +319,7 @@ def create_key_descriptor(x509_certificate_content: bytes):
return MD("KeyDescriptor", *args, **kwargs)


def create_service_catalogus(conf, validate=True):
def create_service_catalogus(conf: EHerkenningConfig, validate: bool = True) -> bytes:
"""
https://afsprakenstelsel.etoegang.nl/display/as/Service+catalog
"""
Expand Down Expand Up @@ -403,8 +405,8 @@ def create_service_catalogus(conf, validate=True):


def get_metadata_eherkenning_requested_attributes(
conf: dict, service_id: str
) -> List[dict]:
conf: ServiceConfig, service_id: str
) -> list[dict]:
# There needs to be a RequestedAttribute element where the name is the ServiceID
# https://afsprakenstelsel.etoegang.nl/display/as/DV+metadata+for+HM
requested_attributes = [{"name": service_id, "isRequired": False}]
Expand All @@ -427,7 +429,7 @@ def get_metadata_eherkenning_requested_attributes(
return requested_attributes


def create_attribute_consuming_services(conf: dict) -> list:
def create_attribute_consuming_services(conf: EHerkenningConfig) -> list[dict]:
attribute_consuming_services = []

for service in conf["services"]:
Expand Down Expand Up @@ -466,15 +468,15 @@ def __init__(
self.loa = loa

@property
def conf(self) -> dict:
def conf(self) -> EHerkenningConfig:
if not hasattr(self, "_conf"):
db_config = EherkenningConfiguration.get_solo()
self._conf = db_config.as_dict()
self._conf.setdefault("acs_path", reverse("eherkenning:acs"))
return self._conf

def create_config_dict(self, conf):
config_dict = super().create_config_dict(conf)
def create_config_dict(self, conf: EHerkenningConfig) -> EHerkenningSAMLConfig:
config_dict: EHerkenningSAMLConfig = super().create_config_dict(conf)

attribute_consuming_services = create_attribute_consuming_services(conf)
with conf["cert_file"].open("r") as cert_file, conf["key_file"].open(
Expand Down Expand Up @@ -504,7 +506,9 @@ def create_config_dict(self, conf):
)
return config_dict

def create_config(self, config_dict):
def create_config(
self, config_dict: EHerkenningSAMLConfig
) -> OneLogin_Saml2_Settings:
config_dict["security"].update(
{
# See comment in the python3-saml for in OneLogin_Saml2_Response.validate_num_assertions (onelogin/saml2/response.py)
Expand Down
95 changes: 95 additions & 0 deletions digid_eherkenning/types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
from pathlib import Path
from typing import TypedDict


class ServiceConfig(TypedDict):
service_uuid: str
service_name: str
attribute_consuming_service_index: str
service_instance_uuid: str
service_description: str
service_description_url: str
service_url: str
loa: str
privacy_policy_url: str
herkenningsmakelaars_id: str
requested_attributes: str
service_restrictions_allowed: str
entity_concerned_types_allowed: list[dict]
language: str
classifiers: list[str] | None


class EHerkenningConfig(TypedDict):
base_url: str
acs_path: str
entity_id: str
metadata_file: str
cert_file: Path
key_file: Path
service_entity_id: str
oin: str
services: list[ServiceConfig]
want_assertions_encrypted: str
want_assertions_signed: str
key_passphrase: str
signature_algorithm: str
digest_algorithm: str
technical_contact_person_telephone: str | None
technical_contact_person_email: str | None
organization: str
organization_name: str
artifact_resolve_content_type: str


class ServiceProviderSAMLConfig(TypedDict):
entityId: str
assertionConsumerService: dict
singleLogoutService: dict
attributeConsumingServices: list[dict]
NameIDFormat: str
x509cert: str
privateKey: str
privateKeyPassphrase: str | None


class IdentityProviderSAMLConfig(TypedDict):
entityId: str
singleSignOnService: dict
singleLogoutService: dict
x509cert: str


class SecuritySAMLConfig(TypedDict):
nameIdEncrypted: bool
authnRequestsSigned: bool
logoutRequestSigned: bool
logoutResponseSigned: bool
signMetadata: bool
wantMessagesSigned: bool
wantAssertionsSigned: bool
wantAssertionsEncrypted: bool
wantNameId: bool
wantNameIdEncrypted: bool
wantAttributeStatement: bool
requestedAuthnContext: bool | list[str]
requestedAuthnContextComparison: str
failOnAuthnContextMismatch: bool
metadataValidUntil: str | None
metadataCacheDuration: str | None
allowSingleLabelDomains: bool
signatureAlgorithm: str
digestAlgorithm: str
allowRepeatAttributeName: bool
rejectDeprecatedAlgorithm: bool
disableSignatureWrappingProtection: bool


class EHerkenningSAMLConfig(TypedDict):
strict: bool
debug: bool
sp: ServiceProviderSAMLConfig
idp: IdentityProviderSAMLConfig
security: SecuritySAMLConfig
contactPerson: dict
organization: dict
2 changes: 1 addition & 1 deletion digid_eherkenning/views/eherkenning.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def get_attribute_consuming_service_index(self) -> Optional[str]:

#
# TODO: It might be a good idea to change this to a post-verb.
# I can't think of any realy attack-vectors, but seems like a good
# I can't think of any relay attack-vectors, but seems like a good
# idea anyways.
#
def get_context_data(self, **kwargs):
Expand Down

0 comments on commit 46eda33

Please sign in to comment.