Source code for request.message_parser.base

"""Provides the `PkiMessageParser` class for parsing PKI messages."""
from abc import ABC, abstractmethod

from pki.models import DomainModel
from request.request_context import BaseCertificateRequestContext, BaseRequestContext
from trustpoint.logger import LoggerMixin


[docs] class ParsingComponent(ABC): """Abstract base class for components in the composite parsing pattern.""" @abstractmethod
[docs] def parse(self, context: BaseRequestContext) -> None | BaseRequestContext: """Execute parsing logic and store results in the context."""
[docs] class DomainParsing(ParsingComponent, LoggerMixin): """Parses and validates the domain from the request context object."""
[docs] def parse(self, context: BaseRequestContext) -> None: """Extract and validate the domain, then add it to the context.""" domain_str = context.domain_str if not domain_str: error_msg = 'Domain str missing in request context, deferring domain resolution to authentication step' self.logger.warning(error_msg) return if domain_str == '.aoki': self.logger.info('Special domain ".aoki" detected, deferring domain resolution to authentication step') return domain = self._extract_requested_domain(domain_str) context.domain = domain self.logger.info("Domain parsing successful: Domain '%s'", domain_str)
def _extract_requested_domain(self, domain_name: str) -> DomainModel: """Validate and fetch the domain object by name.""" try: domain = DomainModel.objects.get(unique_name=domain_name) except DomainModel.DoesNotExist as e: error_message = f"Domain '{domain_name}' does not exist." self.logger.warning("Domain lookup failed: Domain '%s' does not exist", domain_name) raise ValueError(error_message) from e except DomainModel.MultipleObjectsReturned as e: error_message = f"Multiple domains found for '{domain_name}'." self.logger.warning("Domain lookup failed: Multiple domains found for '%s'", domain_name) raise ValueError(error_message) from e else: self.logger.debug("Domain lookup successful: Found domain '%s'", domain_name) return domain
[docs] class CertProfileParsing(ParsingComponent, LoggerMixin): """Parses the certificate profile from the request context object."""
[docs] def parse(self, context: BaseRequestContext) -> None: """Extract and validate the certificate profile, then add it to the context.""" if not isinstance(context, BaseCertificateRequestContext): # Not a certificate request context; skip parsing profile return certprofile_str = context.cert_profile_str if not certprofile_str: error_message = 'Certificate profile is missing in the request context.' self.logger.warning('Certificate profile parsing failed: Profile string is missing') raise ValueError(error_message) self.logger.info("Certificate profile parsing successful: Profile '%s'", certprofile_str)
[docs] class CompositeParsing(ParsingComponent, LoggerMixin): """Composite parser to group multiple parsing strategies.""" def __init__(self) -> None: """Initialize the composite parser with an empty list of components."""
[docs] self.components: list[ParsingComponent] = []
[docs] def add(self, component: ParsingComponent) -> None: """Add a parsing component to the composite parser.""" self.components.append(component)
[docs] def remove(self, component: ParsingComponent) -> None: """Remove a parsing component from the composite parser.""" if component in self.components: self.components.remove(component) self.logger.debug('Removed parsing component: %(component_name)s', extra={'component_name': component.__class__.__name__}) else: error_message = f'Attempted to remove non-existent parsing component: {component.__class__.__name__}' self.logger.warning(error_message) raise ValueError(error_message)
[docs] def parse(self, context: BaseRequestContext) -> BaseRequestContext: """Execute all child parsers, returning the updated type-narrowed context.""" self.logger.debug('Starting composite parsing with %i components', len(self.components)) for i, component in enumerate(self.components): try: ret_val = component.parse(context) if isinstance(ret_val, BaseRequestContext): context = ret_val self.logger.debug('Parsing component %s completed successfully', component.__class__.__name__) except ValueError as e: error_message = f'{component.__class__.__name__}: {e}' self.logger.warning('Parsing component %s failed: %s', component.__class__.__name__, str(e)) self.logger.exception( 'Composite parsing failed at component %s/%s: %s', i + 1, len(self.components), component.__class__.__name__) raise ValueError(error_message) from e except Exception as e: error_message = f'Unexpected error in {component.__class__.__name__}: {e}' self.logger.exception('Unexpected error in parsing component %s', component.__class__.__name__) self.logger.exception( 'Composite parsing failed at component %s/%s: %s', i + 1, len(self.components), component.__class__.__name__) raise ValueError(error_message) from e self.logger.info('Composite parsing successful. All %i components completed', len(self.components)) return context