fix(aws): raise ArgumentTypeError for parser (#4921)

This commit is contained in:
Pedro Martín
2024-09-03 13:47:43 +02:00
committed by GitHub
parent 989fce300d
commit cfd4019281
5 changed files with 89 additions and 77 deletions
+2 -2
View File
@@ -1245,7 +1245,7 @@ def validate_session_duration(duration: int) -> int:
# Since the range(i,j) goes from i to j-1 we have to j+1
if duration not in range(900, 43201):
raise AWSArgumentTypeValidationError(
original_exception="Session Duration must be between 900 and 43200 seconds.",
message="Session Duration must be between 900 and 43200 seconds.",
file=os.path.basename(__file__),
)
else:
@@ -1274,5 +1274,5 @@ def validate_role_session_name(session_name) -> str:
else:
raise AWSArgumentTypeValidationError(
file=os.path.basename(__file__),
original_exception="Role Session Name must be between 2 and 64 characters and may contain alphanumeric characters, periods, hyphens, and underscores.",
message="Role Session Name must be between 2 and 64 characters and may contain alphanumeric characters, periods, hyphens, and underscores.",
)
+41 -59
View File
@@ -8,188 +8,170 @@ class AWSBaseException(ProwlerException):
(1902, "AWSClientError"): {
"message": "AWS ClientError occurred",
"remediation": "Check your AWS client configuration and permissions.",
"file": "{file}",
"provider": "AWS",
},
(1903, "AWSProfileNotFoundError"): {
"message": "AWS Profile not found",
"remediation": "Ensure the AWS profile is correctly configured, please visit https://docs.aws.amazon.com/cli/v1/userguide/cli-configure-files.html",
"file": "{file}",
"provider": "AWS",
},
(1904, "AWSNoCredentialsError"): {
"message": "No AWS credentials found",
"remediation": "Verify that AWS credentials are properly set up, please visit https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/aws/authentication/ and https://docs.aws.amazon.com/cli/v1/userguide/cli-chap-configure.html",
"file": "{file}",
"provider": "AWS",
},
(1905, "AWSArgumentTypeValidationError"): {
"message": "AWS argument type validation error",
"remediation": "Check the provided argument types specific to AWS and ensure they meet the required format. For session duration check: https://docs.aws.amazon.com/singlesignon/latest/userguide/howtosessionduration.html and for role session name check: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_terms-and-concepts.html#iam-term-role-session-name",
"file": "{file}",
"provider": "AWS",
},
(1906, "AWSSetUpSessionError"): {
"message": "AWS session setup error",
"remediation": "Check the AWS session setup and ensure it is properly configured, please visit https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html and check if the provided profile has the necessary permissions.",
"file": "{file}",
"provider": "AWS",
},
(1907, "AWSIAMRoleARNRegionNotEmtpy"): {
"message": "AWS IAM Role ARN region is not empty",
"remediation": "Check the AWS IAM Role ARN region and ensure it is empty, visit https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html#identifiers-arns for more information.",
"file": "{file}",
"provider": "AWS",
},
(1908, "AWSIAMRoleARNPartitionEmpty"): {
"message": "AWS IAM Role ARN partition is empty",
"remediation": "Check the AWS IAM Role ARN partition and ensure it is not empty, visit https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html#identifiers-arns for more information.",
"file": "{file}",
"provider": "AWS",
},
(1909, "AWSIAMRoleARNMissingFields"): {
"message": "AWS IAM Role ARN missing fields",
"remediation": "Check the AWS IAM Role ARN and ensure all required fields are present, visit https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html#identifiers-arns for more information.",
"file": "{file}",
"provider": "AWS",
},
(1910, "AWSIAMRoleARNServiceNotIAMnorSTS"): {
"message": "AWS IAM Role ARN service is not IAM nor STS",
"remediation": "Check the AWS IAM Role ARN service and ensure it is either IAM or STS, visit https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html#identifiers-arns for more information.",
"file": "{file}",
"provider": "AWS",
},
(1911, "AWSIAMRoleARNInvalidAccountID"): {
"message": "AWS IAM Role ARN account ID is invalid",
"remediation": "Check the AWS IAM Role ARN account ID and ensure it is a valid 12-digit number, visit https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html#identifiers-arns for more information.",
"file": "{file}",
"provider": "AWS",
},
(1912, "AWSIAMRoleARNInvalidResourceType"): {
"message": "AWS IAM Role ARN resource type is invalid",
"remediation": "Check the AWS IAM Role ARN resource type and ensure it is valid, resources types are: role, user, assumed-role, root, federated-user, visit https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html#identifiers-arns for more information.",
"file": "{file}",
"provider": "AWS",
},
(1913, "AWSIAMRoleARNEmptyResource"): {
"message": "AWS IAM Role ARN resource is empty",
"remediation": "Check the AWS IAM Role ARN resource and ensure it is not empty, visit https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html#identifiers-arns for more information.",
"file": "{file}",
"provider": "AWS",
},
(1914, "AWSAssumeRoleError"): {
"message": "AWS assume role error",
"remediation": "Check the AWS assume role configuration and ensure it is properly set up, please visithttps://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/aws/role-assumption/ and https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_terms-and-concepts.html#iam-term-role-session-name",
"file": "{file}",
"provider": "AWS",
"remediation": "Check the AWS assume role configuration and ensure it is properly set up, please visit https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/aws/role-assumption/ and https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_terms-and-concepts.html#iam-term-role-session-name",
},
}
def __init__(self, code, provider="AWS", file=None, original_exception=None):
def __init__(self, code, file=None, original_exception=None, message=None):
error_info = self.AWS_ERROR_CODES.get((code, self.__class__.__name__))
super().__init__(code, provider, file, original_exception, error_info)
if message:
error_info["message"] = message
super().__init__(
code,
provider="AWS",
file=file,
original_exception=original_exception,
error_info=error_info,
)
class AWSCredentialsError(AWSBaseException):
"""Base class for AWS credentials errors."""
def __init__(self, code, provider="AWS", file=None, original_exception=None):
super().__init__(code, provider, file, original_exception)
def __init__(self, code, file=None, original_exception=None, message=None):
super().__init__(code, file, original_exception, message)
class AWSClientError(AWSCredentialsError):
def __init__(self, file=None, original_exception=None):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
1902, provider="AWS", file=file, original_exception=original_exception
1902, file=file, original_exception=original_exception, message=message
)
class AWSProfileNotFoundError(AWSCredentialsError):
def __init__(self, file=None, original_exception=None):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
1903, provider="AWS", file=file, original_exception=original_exception
1903, file=file, original_exception=original_exception, message=message
)
class AWSNoCredentialsError(AWSCredentialsError):
def __init__(self, file=None, original_exception=None):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
1904, provider="AWS", file=file, original_exception=original_exception
1904, file=file, original_exception=original_exception, message=message
)
class AWSArgumentTypeValidationError(AWSBaseException):
def __init__(self, file=None, original_exception=None):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
1905, provider="AWS", file=file, original_exception=original_exception
1905, file=file, original_exception=original_exception, message=message
)
class AWSSetUpSessionError(AWSBaseException):
def __init__(self, file=None, original_exception=None):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
1906, provider="AWS", file=file, original_exception=original_exception
1906, file=file, original_exception=original_exception, message=message
)
class AWSRoleArnError(AWSBaseException):
"""Base class for AWS role ARN errors."""
def __init__(self, code, provider="AWS", file=None, original_exception=None):
super().__init__(code, provider, file, original_exception)
def __init__(self, code, file=None, original_exception=None, message=None):
super().__init__(code, file, original_exception, message)
class AWSIAMRoleARNRegionNotEmtpy(AWSRoleArnError):
def __init__(self, file=None, original_exception=None):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
1907, provider="AWS", file=file, original_exception=original_exception
1907, file=file, original_exception=original_exception, message=message
)
class AWSIAMRoleARNPartitionEmpty(AWSRoleArnError):
def __init__(self, file=None, original_exception=None):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
1908, provider="AWS", file=file, original_exception=original_exception
1908, file=file, original_exception=original_exception, message=message
)
class AWSIAMRoleARNMissingFields(AWSRoleArnError):
def __init__(self, file=None, original_exception=None):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
1909, provider="AWS", file=file, original_exception=original_exception
1909, file=file, original_exception=original_exception, message=message
)
class AWSIAMRoleARNServiceNotIAMnorSTS(AWSRoleArnError):
def __init__(self, file=None, original_exception=None):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
1910, provider="AWS", file=file, original_exception=original_exception
1910, file=file, original_exception=original_exception, message=message
)
class AWSIAMRoleARNInvalidAccountID(AWSRoleArnError):
def __init__(self, file=None, original_exception=None):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
1911, provider="AWS", file=file, original_exception=original_exception
1911, file=file, original_exception=original_exception, message=message
)
class AWSIAMRoleARNInvalidResourceType(AWSRoleArnError):
def __init__(self, file=None, original_exception=None):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
1912, provider="AWS", file=file, original_exception=original_exception
1912, file=file, original_exception=original_exception, message=message
)
class AWSIAMRoleARNEmptyResource(AWSRoleArnError):
def __init__(self, file=None, original_exception=None):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
1913, provider="AWS", file=file, original_exception=original_exception
1913, file=file, original_exception=original_exception, message=message
)
class AWSAssumeRoleError(AWSBaseException):
def __init__(self, file=None, original_exception=None):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
1914, provider="AWS", file=file, original_exception=original_exception
1914, file=file, original_exception=original_exception, message=message
)
@@ -1,11 +1,7 @@
from argparse import ArgumentTypeError, Namespace
from re import search
from re import fullmatch, search
from prowler.providers.aws.aws_provider import (
get_aws_available_regions,
validate_role_session_name,
validate_session_duration,
)
from prowler.providers.aws.aws_provider import get_aws_available_regions
from prowler.providers.aws.config import ROLE_SESSION_NAME
from prowler.providers.aws.lib.arn.arn import arn_type
@@ -172,6 +168,42 @@ def init_parser(self):
)
def validate_session_duration(session_duration: int) -> int:
"""validate_session_duration validates that the input session_duration is valid"""
duration = int(session_duration)
# Since the range(i,j) goes from i to j-1 we have to j+1
if duration not in range(900, 43201):
raise ArgumentTypeError(
"Session duration must be between 900 and 43200 seconds"
)
else:
return duration
def validate_role_session_name(session_name) -> str:
"""
Validates that the role session name is valid.
Args:
session_name (str): The role session name to be validated.
Returns:
str: The validated role session name.
Raises:
ArgumentTypeError: If the role session name is invalid.
Documentation:
- AWS STS AssumeRole API: https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html
"""
if fullmatch(r"[\w+=,.@-]{2,64}", session_name):
return session_name
else:
raise ArgumentTypeError(
"Role session name must be between 2 and 64 characters long and may contain alphanumeric characters, hyphens, underscores, plus signs, equal signs, commas, periods, at signs, and tildes."
)
def validate_arguments(arguments: Namespace) -> tuple[bool, str]:
"""validate_arguments returns {True, "} if the provider arguments passed are valid and can be used together. It performs an extra validation, specific for the AWS provider, apart from the argparse lib."""
+3 -4
View File
@@ -6,7 +6,6 @@ from mock import patch
from prowler.lib.cli.parser import ProwlerArgumentParser
from prowler.providers.aws.config import ROLE_SESSION_NAME
from prowler.providers.aws.exceptions.exceptions import AWSArgumentTypeValidationError
from prowler.providers.aws.lib.arguments.arguments import (
validate_bucket,
validate_role_session_name,
@@ -1326,13 +1325,13 @@ class Test_Parser:
"role-name?",
]
for role_name in bad_role_names:
with pytest.raises(AWSArgumentTypeValidationError) as argument_error:
with pytest.raises(ArgumentTypeError) as argument_error:
validate_role_session_name(role_name)
assert argument_error.type == AWSArgumentTypeValidationError
assert argument_error.type == ArgumentTypeError
assert (
argument_error.value.args[0]
== "[1905] AWS argument type validation error - Role Session Name must be between 2 and 64 characters and may contain alphanumeric characters, periods, hyphens, and underscores."
== "Role session name must be between 2 and 64 characters long and may contain alphanumeric characters, hyphens, underscores, plus signs, equal signs, commas, periods, at signs, and tildes."
)
def test_validate_role_session_name_valid_role_names(self):
+5 -6
View File
@@ -1291,9 +1291,8 @@ aws:
) # No profile to avoid ProfileNotFound error
assert exception.type == AWSNoCredentialsError
assert (
"AWSNoCredentialsError[1904]: No AWS credentials found - Unable to locate credentials"
in str(exception.value)
assert "AWSNoCredentialsError[1904]: No AWS credentials found" in str(
exception.value
)
@mock_aws
@@ -1334,7 +1333,7 @@ aws:
assert exception.type == AWSArgumentTypeValidationError
assert (
exception.value.args[0]
== "[1905] AWS argument type validation error - Session Duration must be between 900 and 43200 seconds."
== "[1905] Session Duration must be between 900 and 43200 seconds."
)
@mock_aws
@@ -1354,7 +1353,7 @@ aws:
assert isinstance(connection.error, AWSArgumentTypeValidationError)
assert (
connection.error.args[0]
== "[1905] AWS argument type validation error - Session Duration must be between 900 and 43200 seconds."
== "[1905] Session Duration must be between 900 and 43200 seconds."
)
@mock_aws
@@ -1370,7 +1369,7 @@ aws:
assert exception.type == AWSArgumentTypeValidationError
assert (
exception.value.args[0]
== "[1905] AWS argument type validation error - Role Session Name must be between 2 and 64 characters and may contain alphanumeric characters, periods, hyphens, and underscores."
== "[1905] Role Session Name must be between 2 and 64 characters and may contain alphanumeric characters, periods, hyphens, and underscores."
)
@mock_aws