-
Notifications
You must be signed in to change notification settings - Fork 0
Design Patterns and Abstractions
- Introduction
- Data Class Mapping Pattern
- Protocol Abstraction Pattern
- Feature Flagging System
- Extensible Extension System
- Code Maintainability Benefits
- Architectural Impact
- Best Practices
The Post-Quantum WebAuthn Platform employs sophisticated design patterns and abstractions that enable flexible, maintainable, and extensible code architecture. This document explores four key architectural patterns: the Data Class Mapping pattern, Protocol Abstraction pattern, Feature Flagging system, and Extensible Extension system. These patterns work together to provide a robust foundation for implementing post-quantum cryptographic protocols while maintaining backward compatibility and ease of maintenance.
The platform implements a powerful dual-access pattern through two base classes that enable seamless conversion between attribute-based and dictionary-style access to data objects.
classDiagram
class _DataClassMapping {
<<abstract>>
+__post_init__()
+_get_field_key(field) _T
+__iter__() Iterator
+__len__() int
+__getitem__(key) Any
+_parse_value(t, value) Any
+from_dict(data) Self
}
class _JsonDataObject {
+_get_field_key(field) str
+__getitem__(key) Any
+_parse_value(t, value) Any
}
class _WebAuthnDataObject {
+__getitem__(key) Any
+from_dict(data) Self
}
class PublicKeyCredentialCreationOptions {
+rp PublicKeyCredentialRpEntity
+user PublicKeyCredentialUserEntity
+challenge bytes
+pub_key_cred_params Sequence
+timeout Optional[int]
+exclude_credentials Optional[Sequence]
+authenticator_selection Optional[AuthenticatorSelectionCriteria]
+attestation Optional[AttestationConveyancePreference]
+extensions Optional[Mapping]
}
_DataClassMapping <|-- _JsonDataObject
_JsonDataObject <|-- _WebAuthnDataObject
_WebAuthnDataObject <|-- PublicKeyCredentialCreationOptions
Diagram sources
- fido2/utils.py
- fido2/webauthn.py
The _DataClassMapping base class provides a foundation for creating data classes that can be accessed both as attributes and dictionary-style. Key features include:
- Automatic Field Mapping: Fields are automatically mapped to keys using reflection
- Type Safety: Automatic type conversion and validation during deserialization
- Flexible Serialization: Support for custom serialization and deserialization logic
- Optional Value Handling: Graceful handling of None values and optional fields
The _JsonDataObject subclass extends this functionality specifically for JSON serialization, automatically converting bytes to websafe base64 encoding and vice versa.
Section sources
- fido2/utils.py
- fido2/webauthn.py
The pattern enables intuitive access patterns:
# Dictionary-style access
options = PublicKeyCredentialCreationOptions.from_dict({
"rp": {"name": "Example", "id": "example.com"},
"user": {"name": "user", "id": "user_id"},
"challenge": "challenge_bytes",
"pubKeyCredParams": [...]
})
# Attribute-style access
assert options.rp.name == "Example"
assert options.user.id == b"user_id"
# Mixed access patterns
assert options["rp"]["name"] == "Example"
assert options.rp["name"] == "Example"The CTAP2 protocol implementation demonstrates a sophisticated command-response abstraction that encapsulates the complexity of the underlying protocol while providing a clean interface.
classDiagram
class Ctap2 {
+CMD enum
+device CtapDevice
+_strict_cbor bool
+_max_msg_size int
+_info Info
+send_cbor(cmd, data, event, on_keepalive) Mapping
+get_info() Info
+make_credential(...) AttestationResponse
+get_assertion(...) AssertionResponse
+reset(...)
+client_pin(...)
+credential_mgmt(...)
+bio_enrollment(...)
+selection(...)
+large_blobs(...)
+config(...)
}
class _CborDataObject {
+_get_field_key(field) int
}
class Info {
+versions list[str]
+extensions list[str]
+aaguid Aaguid
+options dict[str, bool]
+max_msg_size int
+pin_uv_protocols list[int]
+algorithms list[dict]
}
class AttestationResponse {
+fmt str
+auth_data AuthenticatorData
+att_stmt dict[str, Any]
+ep_att bool
+large_blob_key bytes
+unsigned_extension_outputs dict[str, Any]
}
class AssertionResponse {
+credential Mapping[str, Any]
+auth_data AuthenticatorData
+signature bytes
+user dict[str, Any]
+number_of_credentials int
+user_selected bool
+large_blob_key bytes
+verify(client_param, public_key)
+from_ctap1(app_param, credential, authentication) AssertionResponse
}
Ctap2 --> _CborDataObject
_CborDataObject <|-- Info
_CborDataObject <|-- AttestationResponse
_CborDataObject <|-- AssertionResponse
Diagram sources
- fido2/ctap2/base.py
The protocol abstraction includes comprehensive error handling through a structured approach:
flowchart TD
A[Send CBOR Request] --> B{Validate Message Size}
B --> |Too Large| C[Throw CtapError.REQUEST_TOO_LARGE]
B --> |OK| D[Send to Device]
D --> E{Receive Response}
E --> |Status != 0x00| F[Throw CtapError with Status]
E --> |Empty Response| G[Return Empty Dict]
E --> |Has Content| H[Decode CBOR]
H --> I{Strict CBOR Validation}
I --> |Invalid| J[Throw ValueError]
I --> |Valid| K[Return Decoded Data]
F --> L[Error Propagation]
C --> L
J --> L
G --> L
K --> M[Success Response]
Diagram sources
- fido2/ctap2/base.py
Section sources
- fido2/ctap2/base.py
The feature flagging system provides controlled activation of optional functionality with clear deprecation warnings and migration paths.
classDiagram
class _Feature {
-_enabled Optional[bool]
-_name str
-_desc str
+enabled bool
+enabled setter
+require(state : bool)
+warn()
}
class FeatureNotEnabledError {
+__init__(message : str)
}
class _FeatureState {
+enabled : bool
+name : str
+description : str
}
_Feature --> _FeatureState
_Feature --> FeatureNotEnabledError
Diagram sources
- fido2/features.py
The feature flag system provides:
- Safe Activation: Prevents reconfiguration after initialization
- Graceful Degradation: Warns users about deprecated usage
- Clear Migration Paths: Provides actionable upgrade instructions
- Type Safety: Ensures proper feature state management
Section sources
- fido2/features.py
# Enable feature explicitly
import fido2.features
fido2.features.webauthn_json_mapping.enabled = True
# Usage with automatic warnings
if fido2.features.webauthn_json_mapping.enabled:
# New behavior
pass
else:
# Legacy behavior
passThe extension system allows adding new CTAP2 features without modifying core protocol code, following the Open/Closed Principle.
classDiagram
class Ctap2Extension {
<<abstract>>
+is_supported(ctap : Ctap2) bool
+make_credential(ctap, options, pin_protocol) RegistrationExtensionProcessor
+get_assertion(ctap, options, pin_protocol) AuthenticationExtensionProcessor
}
class ExtensionProcessor {
<<abstract>>
+permissions ClientPin.PERMISSION
+inputs dict[str, Any]
+outputs dict[str, Any]
}
class RegistrationExtensionProcessor {
+prepare_inputs(pin_token : bytes) dict[str, Any]
+prepare_outputs(response : AttestationResponse, pin_token : bytes) dict[str, Any]
}
class AuthenticationExtensionProcessor {
+prepare_inputs(selected : PublicKeyCredentialDescriptor, pin_token : bytes) dict[str, Any]
+prepare_outputs(response : AssertionResponse, pin_token : bytes) dict[str, Any]
}
class HmacSecretExtension {
+NAME str
+MC_NAME str
+SALT_LEN int
+is_supported(ctap) bool
+make_credential(ctap, options, pin_protocol) RegistrationExtensionProcessor
+get_assertion(ctap, options, pin_protocol) AuthenticationExtensionProcessor
}
class LargeBlobExtension {
+NAME str
+is_supported(ctap) bool
+make_credential(ctap, options, pin_protocol) RegistrationExtensionProcessor
+get_assertion(ctap, options, pin_protocol) AuthenticationExtensionProcessor
}
Ctap2Extension <|-- HmacSecretExtension
Ctap2Extension <|-- LargeBlobExtension
ExtensionProcessor <|-- RegistrationExtensionProcessor
ExtensionProcessor <|-- AuthenticationExtensionProcessor
Diagram sources
- fido2/ctap2/extensions.py
The platform includes several built-in extensions that demonstrate the extensibility pattern:
| Extension | Purpose | Key Features |
|---|---|---|
HmacSecretExtension |
Pseudorandom function and HMAC secret | Supports both PRF and legacy HMAC modes |
LargeBlobExtension |
Large blob storage | Read/write operations with PIN protection |
CredBlobExtension |
Credential blob storage | Per-credential arbitrary data storage |
CredProtectExtension |
Credential protection policies | User verification enforcement |
MinPinLengthExtension |
Minimum PIN length enforcement | Dynamic PIN length requirements |
Section sources
- fido2/ctap2/extensions.py
New extensions can be easily registered:
# Add custom extension to default list
_DEFAULT_EXTENSIONS.append(MyCustomExtension())
# Or create custom extension list
custom_extensions = [
HmacSecretExtension(),
MyCustomExtension(),
YetAnotherExtension()
]The design patterns significantly enhance code readability through:
- Consistent Interfaces: All data classes follow the same access patterns
- Clear Separation: Protocol logic is separated from data modeling
- Intuitive APIs: Methods and properties follow predictable naming conventions
- Self-documenting: Type hints and docstrings provide immediate context
The modular architecture facilitates comprehensive testing:
flowchart LR
A[Unit Tests] --> B[Mock Devices]
A --> C[Stub Responses]
D[Integration Tests] --> E[Real Device Communication]
D --> F[End-to-end Scenarios]
G[Property Tests] --> H[Randomized Inputs]
G --> I[Edge Case Validation]
B --> J[Isolated Component Testing]
C --> J
E --> K[Functional Verification]
F --> K
H --> L[Robustness Validation]
I --> L
The patterns provide excellent debugging capabilities:
- Rich Error Messages: Detailed error information with context
- Serialization Support: Easy inspection of data structures
- Logging Integration: Comprehensive logging throughout the stack
- State Inspection: Easy examination of internal state
Section sources
- tests/test_webauthn.py
- tests/test_ctap2.py
The design patterns support scalable development:
- Incremental Adoption: New features can be added without breaking changes
- Backward Compatibility: Existing code continues to work unchanged
- Performance Optimization: Efficient serialization and caching mechanisms
- Memory Management: Proper resource cleanup and garbage collection
The architecture enhances security through:
- Defense in Depth: Multiple layers of validation and error handling
- Type Safety: Compile-time checking of data structures
- Access Control: Granular permission systems for sensitive operations
- Audit Trails: Comprehensive logging for security monitoring
The patterns are designed for optimal performance:
- Lazy Loading: Data is parsed only when accessed
- Caching: Frequently accessed data is cached efficiently
- Minimal Allocations: Optimized memory usage patterns
- Streaming Support: Large data can be processed incrementally
When creating new data classes:
-
Extend Appropriate Base: Choose between
_DataClassMappingand_JsonDataObjectbased on serialization needs - Use Type Hints: Provide comprehensive type information for better IDE support
-
Implement Proper Validation: Use
__post_init__for data validation - Support Both Access Patterns: Ensure compatibility with both attribute and dictionary access
For protocol-related code:
- Follow Command Pattern: Encapsulate each command in a dedicated method
- Implement Comprehensive Error Handling: Cover all possible failure scenarios
- Use Strong Typing: Leverage Python's type system for safety
- Provide Clear Documentation: Document all public methods and their expected behavior
When developing new extensions:
- Inherit from Ctap2Extension: Follow the established pattern
-
Implement Proper Discovery: Ensure
is_supported()works correctly - Handle Permissions: Respect PIN/UV requirements appropriately
- Test Thoroughly: Verify behavior with various authenticator configurations
For feature flag implementation:
- Use Descriptive Names: Choose clear, meaningful feature names
- Provide Migration Paths: Offer clear upgrade instructions
- Implement Graceful Degradation: Ensure fallback behavior is available
- Document Dependencies: Clearly explain feature interdependencies