Request Pipeline

Overview

The request pipeline processes incoming PKI requests (EST, CMP) through a series of composable stages, each responsible for a specific aspect of request handling. The architecture uses the Composite Pattern throughout to allow flexible composition of validation, parsing, authentication, and authorization logic.

For a comprehensive overview of the credential architecture and component organization, see Credentials - Architecture.

Pipeline Stages:

  1. HTTP Request Validation - Validates HTTP-level attributes (headers, content-type, payload size)

  2. Message Parsing - Parses and validates protocol-specific message content

  3. Authentication - Verifies the authenticity of credentials presented by the client

  4. Authorization - Determines what operations are permitted for the authenticated request

  5. Request Processing - Processes the request to issue certificates or perform other PKI operations

  6. Response Generation - Generates a protocol-specific response

Each stage uses the Composite Pattern with a base component interface, allowing individual components to be composed into more complex operations.

Request Pipeline Flow

The following diagram shows how requests flow through the entire pipeline:

@startuml
start
:Receive HTTP Request;
:HTTP Validation;
if (Valid?) then (yes)
else (no)
    :Return HTTP Error;
    stop
endif
:Message Parsing;
if (Valid?) then (yes)
else (no)
    :Return Parse Error;
    stop
endif
:Authentication;
if (Authentic?) then (yes)
else (no)
    :Return Auth Error;
    stop
endif
:Authorization;
if (Authorized?) then (yes)
else (no)
    :Return Auth Error;
    stop
endif
:Process Request;
if (Success?) then (yes)
else (no)
    :Return Processing Error;
    stop
endif
:Generate Response;
:Return Response;
stop
@enduml

Request Context Hierarchy

The RequestContext hierarchy carries state through the entire pipeline:

@startuml
' Base context for all request types.
class BaseRequestContext {
    + raw_message: HttpRequest
    + protocol: str
    + operation: str
    + domain_str: str
    + cert_profile_str: str
    --
    + domain: DomainModel | None
    + device: DeviceModel | None
}

' Validation request contexts.
class EstBaseRequestContext {
    + est_username: str | None
    + est_password: str | None
    + client_certificate: x509.Certificate | None
    + client_intermediate_certificate: list[x509.Certificate] | None
}

class CmpBaseRequestContext {
    + parsed_message: rfc4210.PKIMessage | None
    + cmp_shared_secret: str | None
    + client_certificate: x509.Certificate | None
}

' Certificate request contexts.
class EstCertificateRequestContext {
    + cert_requested: x509.CertificateSigningRequest | None
    + est_encoding: str | None
}

class CmpCertificateRequestContext {
    + parsed_message: rfc4210.PKIMessage
}

' Revocation request contexts.
class CmpRevocationRequestContext {
    + parsed_message: rfc4210.PKIMessage
}

' Relationships.
BaseRequestContext <|-- EstBaseRequestContext
BaseRequestContext <|-- CmpBaseRequestContext
EstBaseRequestContext <|-- EstCertificateRequestContext
CmpBaseRequestContext <|-- CmpCertificateRequestContext
CmpBaseRequestContext <|-- CmpRevocationRequestContext

@enduml

HTTP Request Validator Module Diagram

@startuml
' General interface for all validation classes.
interface ValidationComponent {
    + validate(context: RequestContext)
}

' Composite class for grouping and executing multiple validation rules.
class CompositeValidation {
    + components: list[ValidationComponent]
    + add(component: ValidationComponent)
    + remove(component: ValidationComponent)
    + validate(context: RequestContext)
}

' Composite validators for CMP and EST-specific requests.
class CmpHttpRequestValidator {
    + __init__()
    + validate(context: RequestContext)
}

class EstHttpRequestValidator {
    + __init__()
    + validate(context: RequestContext)
}

' Individual validation components.
class PayloadSizeValidation {
    + max_payload_size: int
    + validate(context: RequestContext)
}

class ContentTypeValidation {
    + expected_content_type: str
    + validate(context: RequestContext)
}

class AcceptHeaderValidation {
    + allowed_content_types: list[str]
    + validate(context: RequestContext)
}

class AuthorizationHeaderValidation {
    + validate(context: RequestContext)
}

class ClientCertificateValidation {
    + validate(context: RequestContext)
}

class IntermediateCertificatesValidation {
    + validate(context: RequestContext)
}

class ContentTransferEncodingValidation {
    + validate(context: RequestContext)
}

' Dependency relationship with RequestContext.
class RequestContext {
    + raw_message: Request
    + parsed_message: bytes
    + est_username: str
    + est_password: str
    + client_certificate: x509.Certificate
    + client_intermediate_certificate: list[x509.Certificate]
}

' Relationships.
ValidationComponent <|-- CompositeValidation
CompositeValidation <|-- CmpHttpRequestValidator
CompositeValidation <|-- EstHttpRequestValidator
ValidationComponent <|-- PayloadSizeValidation
ValidationComponent <|-- ContentTypeValidation
ValidationComponent <|-- AcceptHeaderValidation
ValidationComponent <|-- AuthorizationHeaderValidation
ValidationComponent <|-- ClientCertificateValidation
ValidationComponent <|-- IntermediateCertificatesValidation
ValidationComponent <|-- ContentTransferEncodingValidation

' Composite relationships.
CompositeValidation o--> ValidationComponent : "validates using"
CompositeValidation --> RequestContext : "uses"
CmpHttpRequestValidator --> CompositeValidation : "extends"
EstHttpRequestValidator --> CompositeValidation : "extends"
PayloadSizeValidation --> RequestContext : "validates payload size"
ContentTypeValidation --> RequestContext : "checks content type"
AcceptHeaderValidation --> RequestContext : "checks 'Accept'"
AuthorizationHeaderValidation --> RequestContext : "extracts credentials"
ClientCertificateValidation --> RequestContext : "verifies SSL client cert"
IntermediateCertificatesValidation --> RequestContext : "validates CA chain"
ContentTransferEncodingValidation --> RequestContext : "decodes base64"

@enduml

Message Parser Module Diagram

@startuml
' General interface for all parsing components.
interface ParsingComponent {
    + parse(context: RequestContext)
}

' Composite parser to group and execute individual parsing strategies.
class CompositeParsing {
    + components: list[ParsingComponent]
    + add(component: ParsingComponent)
    + remove(component: ParsingComponent)
    + parse(context: RequestContext)
}

' Specialized composite parsers for specific protocols.
class CmpMessageParser {
    + __init__()
    + parse(context: RequestContext)
}

class EstMessageParser {
    + __init__()
    + parse(context: RequestContext)
}

' Individual parsing components.
class EstPkiMessageParsing {
    + parse(context: RequestContext)
}

class CmpPkiMessageParsing {
    + parse(context: RequestContext)
}

class EstCsrSignatureVerification {
    + parse(context: RequestContext)
}

class DomainParsing {
    + parse(context: RequestContext)
}

class CertProfileParsing {
    + parse(context: RequestContext)
}

' Dependency relationship with RequestContext.
class RequestContext {
    + raw_message: Request
    + domain_str: str
    + cert_profile_str: str
    + cert_requested: x509.CertificateSigningRequest
    + domain: DomainModel
    + parsed_message: PKIMessage
    + est_encoding: str
}

' Relationships.
ParsingComponent <|-- CompositeParsing
CompositeParsing <|-- CmpMessageParser
CompositeParsing <|-- EstMessageParser
ParsingComponent <|-- EstPkiMessageParsing
ParsingComponent <|-- CmpPkiMessageParsing
ParsingComponent <|-- EstCsrSignatureVerification
ParsingComponent <|-- DomainParsing
ParsingComponent <|-- CertProfileParsing

' Composite dependencies.
CompositeParsing o--> ParsingComponent : "parses with"
CompositeParsing --> RequestContext : "uses"
CmpMessageParser --> CompositeParsing : "extends"
EstMessageParser --> CompositeParsing : "extends"
EstPkiMessageParsing --> RequestContext : "parses CSR"
CmpPkiMessageParsing --> RequestContext : "handles CMP messages"
EstCsrSignatureVerification --> RequestContext : "verifies CSR signature"
DomainParsing --> RequestContext : "validates domain"
CertProfileParsing --> RequestContext : "parses certificate template"

@enduml

Authentication Module Diagram

@startuml
' General interface for all authentication classes.
interface AuthenticationComponent {
    + authenticate(context: RequestContext)
}

' Defines the structure for aggregating multiple authentications.
class CompositeAuthentication {
    + components: list[AuthenticationComponent]
    + add(component: AuthenticationComponent)
    + remove(component: AuthenticationComponent)
    + authenticate(context: RequestContext)
}

' Composite for EST-specific authentication methods.
class EstAuthentication {
    + __init__()
    + authenticate(context: RequestContext)
}

' Individual concrete authentication implementations for specialized use cases.
class UsernamePasswordAuthentication {
    + authenticate(context: RequestContext)
}

class ClientCertificateAuthentication {
    + authenticate(context: RequestContext)
}

class ReenrollmentAuthentication {
    + authenticate(context: RequestContext)
}

class IDevIDAuthentication {
    + authenticate(context: RequestContext)
}

' Dependency relationship with request context.
class RequestContext {
    + est_username: str
    + est_password: str
    + client_certificate: Certificate
    + cert_requested: Certificate
    + raw_message: Message
    + device: DeviceModel
    + domain: DomainModel
}

' Relationship between AuthenticationComponent and implementations.
AuthenticationComponent <|-- UsernamePasswordAuthentication
AuthenticationComponent <|-- ClientCertificateAuthentication
AuthenticationComponent <|-- ReenrollmentAuthentication
AuthenticationComponent <|-- IDevIDAuthentication
AuthenticationComponent <|-- CompositeAuthentication
CompositeAuthentication <|-- EstAuthentication

' Internal dependencies
CompositeAuthentication o--> AuthenticationComponent : components
CompositeAuthentication --> RequestContext : uses
EstAuthentication --> CompositeAuthentication : extends

UsernamePasswordAuthentication --> RequestContext : reads credentials
ClientCertificateAuthentication --> RequestContext : verifies certificate
ReenrollmentAuthentication --> RequestContext : validates re-enrollment
IDevIDAuthentication --> RequestContext : checks IDevID authentication

@enduml

Authorization Module Diagram

@startuml
' General interface for all authorization logic.
interface AuthorizationComponent {
    + authorize(context: RequestContext)
}

' Composite that combines multiple authorization mechanisms.
class CompositeAuthorization {
    + components: list[AuthorizationComponent]
    + add(component: AuthorizationComponent)
    + remove(component: AuthorizationComponent)
    + authorize(context: RequestContext)
}

' Specific composite for EST authorization rules.
class EstAuthorization {
    + __init__()
    + authorize(context: RequestContext)
}

' Concrete authorization rules for different aspects of a request.
class ProtocolAuthorization {
    + allowed_protocols: list[str]
    + authorize(context: RequestContext)
}

class OperationAuthorization {
    + allowed_operations: list[str]
    + authorize(context: RequestContext)
}

class CertificateProfileAuthorization {
    + authorize(context: RequestContext)
}

class DomainScopeValidation {
    + authorize(context: RequestContext)
}

' Dependency: Context object used in all authorization methods.
class RequestContext {
    + protocol: str
    + operation: str
    + cert_profile_str: str
    + domain: DomainModel
    + device: DeviceModel
}

' Relationships between components.
AuthorizationComponent <|-- ProtocolAuthorization
AuthorizationComponent <|-- OperationAuthorization
AuthorizationComponent <|-- CertificateProfileAuthorization
AuthorizationComponent <|-- DomainScopeValidation
AuthorizationComponent <|-- CompositeAuthorization
CompositeAuthorization <|-- EstAuthorization

' Aggregations and dependencies.
CompositeAuthorization o--> AuthorizationComponent : components
CompositeAuthorization --> RequestContext : uses
EstAuthorization --> CompositeAuthorization : extends
ProtocolAuthorization --> RequestContext : reads protocol
OperationAuthorization --> RequestContext : reads operation
CertificateProfileAuthorization --> RequestContext : checks template
DomainScopeValidation --> RequestContext : validates domain

@enduml

Key Concepts

Composite Pattern

Each pipeline stage (validation, parsing, authentication, authorization) uses the Composite Pattern with a base component interface. This allows individual components to be composed into more complex operations, enabling flexible configuration of what rules apply to each protocol and operation.

Request Context

The RequestContext object carries state through the entire pipeline. Different context types (EstCertificateRequestContext, CmpBaseRequestContext, etc.) extend BaseRequestContext to provide protocol-specific attributes while maintaining a consistent interface.

ParsingComponent

Parsing components sequentially process the request context, extracting and validating message content. Examples include:

  • EstAuthorizationHeaderParsing: Extracts HTTP Basic Auth credentials

  • EstPkiMessageParsing: Parses PKCS#10 CSR

  • CmpPkiMessageParsing: Parses CMP PKIMessage

  • DomainParsing: Resolves domain identifier to DomainModel

  • CertProfileParsing: Resolves certificate profile

AuthenticationComponent

Authentication components verify the authenticity of credentials. Unlike authorization, authentication does NOT determine device identity; that happens during authorization. Authentication simply validates that the provided credentials are valid.

AuthorizationComponent

Authorization components determine what operations are allowed. They access the fully populated RequestContext (including domain and device information) to make authorization decisions.

Error Handling

Each stage can raise exceptions with appropriate error messages. Errors are caught at the view level and converted to protocol-specific error responses (EST error messages or CMP PKIFailureInfo).