mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-26 13:24:20 +00:00
fix(api): tighten Azure certificate cap and route oversized/whitespace inputs through the typed error
This commit is contained in:
1 parent
f67cf7c3e5
commit
ef62731c0a
3 files changed
+68
-15
No files matched your search
@@ -21318,7 +21318,7 @@ components:
|
||||
type: string
|
||||
description: Base64-encoded PEM or PKCS#12/PFX bundle containing the certificate
|
||||
and its matching private key for certificate-based authentication.
|
||||
maxLength: 68266
|
||||
maxLength: 68268
|
||||
tenant_id:
|
||||
type: string
|
||||
description: The Azure tenant ID, representing the directory
|
||||
@@ -21371,7 +21371,7 @@ components:
|
||||
type: string
|
||||
description: Base64-encoded PEM or PKCS#12/PFX bundle containing the certificate
|
||||
and its matching private key for certificate-based authentication.
|
||||
maxLength: 68266
|
||||
maxLength: 68268
|
||||
required:
|
||||
- client_id
|
||||
- tenant_id
|
||||
@@ -23469,7 +23469,7 @@ components:
|
||||
type: string
|
||||
description: Base64-encoded PEM or PKCS#12/PFX bundle containing the certificate
|
||||
and its matching private key for certificate-based authentication.
|
||||
maxLength: 68266
|
||||
maxLength: 68268
|
||||
tenant_id:
|
||||
type: string
|
||||
description: The Azure tenant ID, representing the directory where
|
||||
@@ -23522,7 +23522,7 @@ components:
|
||||
type: string
|
||||
description: Base64-encoded PEM or PKCS#12/PFX bundle containing the certificate
|
||||
and its matching private key for certificate-based authentication.
|
||||
maxLength: 68266
|
||||
maxLength: 68268
|
||||
required:
|
||||
- client_id
|
||||
- tenant_id
|
||||
@@ -23936,7 +23936,7 @@ components:
|
||||
type: string
|
||||
description: Base64-encoded PEM or PKCS#12/PFX bundle containing the certificate
|
||||
and its matching private key for certificate-based authentication.
|
||||
maxLength: 68266
|
||||
maxLength: 68268
|
||||
tenant_id:
|
||||
type: string
|
||||
description: The Azure tenant ID, representing the directory
|
||||
@@ -23989,7 +23989,7 @@ components:
|
||||
type: string
|
||||
description: Base64-encoded PEM or PKCS#12/PFX bundle containing the certificate
|
||||
and its matching private key for certificate-based authentication.
|
||||
maxLength: 68266
|
||||
maxLength: 68268
|
||||
required:
|
||||
- client_id
|
||||
- tenant_id
|
||||
@@ -24425,7 +24425,7 @@ components:
|
||||
type: string
|
||||
description: Base64-encoded PEM or PKCS#12/PFX bundle containing the certificate
|
||||
and its matching private key for certificate-based authentication.
|
||||
maxLength: 68266
|
||||
maxLength: 68268
|
||||
tenant_id:
|
||||
type: string
|
||||
description: The Azure tenant ID, representing the directory where
|
||||
@@ -24478,7 +24478,7 @@ components:
|
||||
type: string
|
||||
description: Base64-encoded PEM or PKCS#12/PFX bundle containing the certificate
|
||||
and its matching private key for certificate-based authentication.
|
||||
maxLength: 68266
|
||||
maxLength: 68268
|
||||
required:
|
||||
- client_id
|
||||
- tenant_id
|
||||
|
||||
@@ -370,9 +370,12 @@ class TestAzureProviderSecret:
|
||||
)
|
||||
|
||||
def test_rejects_oversized_certificate_content(self):
|
||||
# Payloads larger than the base64 cap must be rejected at the DRF
|
||||
# field layer before base64 decoding or bundle parsing runs, so a
|
||||
# multi-MB blob cannot exhaust API-worker memory.
|
||||
# Payloads larger than the base64 cap must be rejected inside
|
||||
# `validate_certificate_content` (before base64 decoding or bundle
|
||||
# parsing runs) so a multi-MB blob cannot exhaust API-worker
|
||||
# memory. The typed `azure-certificate-content` code lets JSON:API
|
||||
# clients recognize this as a certificate failure rather than a
|
||||
# generic length violation.
|
||||
from api.v1.serializers import _MAX_CERTIFICATE_CONTENT_LENGTH
|
||||
|
||||
serializer = AzureProviderSecret(
|
||||
@@ -384,6 +387,38 @@ class TestAzureProviderSecret:
|
||||
|
||||
assert not serializer.is_valid()
|
||||
assert "certificate_content" in serializer.errors
|
||||
assert (
|
||||
serializer.errors["certificate_content"][0].code
|
||||
== "azure-certificate-content"
|
||||
)
|
||||
|
||||
def test_tolerates_whitespace_in_certificate_content(self):
|
||||
# A base64 payload with embedded whitespace (CRLF from a Windows
|
||||
# terminal, wrapped copy-paste) must not be rejected as "invalid
|
||||
# base64" — whitespace carries no information in the encoding.
|
||||
import base64
|
||||
|
||||
bundle_b64 = self.certificate_bundle()
|
||||
# Insert CRLF every 64 chars and leading/trailing spaces to mimic
|
||||
# a copy-paste from a terminal export.
|
||||
wrapped = (
|
||||
" "
|
||||
+ "\r\n".join(bundle_b64[i : i + 64] for i in range(0, len(bundle_b64), 64))
|
||||
+ " "
|
||||
)
|
||||
|
||||
serializer = AzureProviderSecret(
|
||||
data={**self.BASE, "certificate_content": wrapped}
|
||||
)
|
||||
|
||||
assert serializer.is_valid(), serializer.errors
|
||||
# The stored value is the whitespace-stripped payload, so the SDK
|
||||
# sees exactly the bytes it would from a clean base64 upload.
|
||||
assert serializer.validated_data["certificate_content"] == bundle_b64
|
||||
# And it still decodes to the original bundle unchanged.
|
||||
assert base64.b64decode(
|
||||
serializer.validated_data["certificate_content"]
|
||||
) == base64.b64decode(bundle_b64)
|
||||
|
||||
def test_mutex_errors_carry_stable_codes(self):
|
||||
# JSON:API clients key on `code`; without it they cannot tell the
|
||||
|
||||
@@ -1793,16 +1793,21 @@ class AwsProviderSecret(serializers.Serializer):
|
||||
# limit on the decoded bundle. Rejects oversized payloads at the request
|
||||
# layer so DRF never allocates the doubled memory that base64 decoding plus
|
||||
# PKCS#12/PEM parsing would need for a multi-MB blob.
|
||||
_MAX_CERTIFICATE_CONTENT_LENGTH = 68266
|
||||
# `((51200 + 2) // 3) * 4` = 68268 base64 chars for a bundle exactly at the
|
||||
# SDK cap. Keep the two constants aligned if either side moves.
|
||||
_MAX_CERTIFICATE_CONTENT_LENGTH = 68268
|
||||
|
||||
|
||||
class AzureProviderSecret(serializers.Serializer):
|
||||
client_id = serializers.CharField()
|
||||
client_secret = serializers.CharField(required=False)
|
||||
tenant_id = serializers.CharField()
|
||||
certificate_content = serializers.CharField(
|
||||
required=False, max_length=_MAX_CERTIFICATE_CONTENT_LENGTH
|
||||
)
|
||||
# The size cap is enforced in `validate_certificate_content` with the
|
||||
# typed `azure-certificate-content` code, not via `max_length=`. DRF's
|
||||
# built-in max-length check runs before per-field validators and emits
|
||||
# `code="max_length"`, which JSON:API clients keyed to the typed
|
||||
# certificate error code cannot recognize as a certificate failure.
|
||||
certificate_content = serializers.CharField(required=False)
|
||||
|
||||
def validate(self, attrs):
|
||||
if attrs.get("client_secret") and attrs.get("certificate_content"):
|
||||
@@ -1820,6 +1825,19 @@ class AzureProviderSecret(serializers.Serializer):
|
||||
def validate_certificate_content(self, certificate_content):
|
||||
"""Validate the Azure certificate and matching private-key bundle."""
|
||||
if certificate_content:
|
||||
# Tolerate whitespace inside the base64 payload: exports from
|
||||
# Windows terminals (CRLF) or wrapped copy-paste survive without
|
||||
# tripping `base64.b64decode(validate=True)`, and the reader is
|
||||
# base64 anyway — internal whitespace carries no information.
|
||||
certificate_content = "".join(certificate_content.split())
|
||||
if len(certificate_content) > _MAX_CERTIFICATE_CONTENT_LENGTH:
|
||||
# Reject oversized payloads with the typed certificate code
|
||||
# so JSON:API clients recognize this as a certificate-content
|
||||
# failure rather than a generic length violation.
|
||||
raise serializers.ValidationError(
|
||||
"Certificate content exceeds the maximum size.",
|
||||
code="azure-certificate-content",
|
||||
)
|
||||
try:
|
||||
certificate_data = base64.b64decode(certificate_content, validate=True)
|
||||
validate_certificate_bundle(certificate_data)
|
||||
|
||||
Reference in new issue
Block a user