diff --git a/dojo/api_v2/serializers.py b/dojo/api_v2/serializers.py index 5109bd068f0..7b9d9428769 100644 --- a/dojo/api_v2/serializers.py +++ b/dojo/api_v2/serializers.py @@ -551,8 +551,7 @@ def validate(self, data): if self.context["request"].method in ["PATCH", "PUT"] and "password" in data: msg = "Update of password though API is not allowed" raise ValidationError(msg) - - if self.context["request"].method == "POST" and "password" not in data: + if self.context["request"].method == "POST" and "password" not in data and settings.REQUIRE_PASSWORD_ON_USER: msg = "Passwords must be supplied for new users" raise ValidationError(msg) return super().validate(data) diff --git a/dojo/api_v2/views.py b/dojo/api_v2/views.py index 9e8368d6277..f9ebd4cd452 100644 --- a/dojo/api_v2/views.py +++ b/dojo/api_v2/views.py @@ -299,6 +299,7 @@ def get_queryset(self): # Authorization: object-based # @extend_schema_view(**schema_with_prefetch()) +# Nested models with prefetch make the response schema too long for Swagger UI class EndPointViewSet( PrefetchDojoModelViewSet, ): @@ -354,7 +355,8 @@ def generate_report(self, request, pk=None): # Authorization: object-based -@extend_schema_view(**schema_with_prefetch()) +# @extend_schema_view(**schema_with_prefetch()) +# Nested models with prefetch make the response schema too long for Swagger UI class EndpointStatusViewSet( PrefetchDojoModelViewSet, ): @@ -383,7 +385,8 @@ def get_queryset(self): # Authorization: object-based -@extend_schema_view(**schema_with_prefetch()) +# @extend_schema_view(**schema_with_prefetch()) +# Nested models with prefetch make the response schema too long for Swagger UI class EngagementViewSet( PrefetchDojoModelViewSet, ra_api.AcceptedRisksMixin, @@ -637,7 +640,8 @@ def download_file(self, request, file_id, pk=None): return generate_file_response(file_object) -@extend_schema_view(**schema_with_prefetch()) +# @extend_schema_view(**schema_with_prefetch()) +# Nested models with prefetch make the response schema too long for Swagger UI class RiskAcceptanceViewSet( PrefetchDojoModelViewSet, ): @@ -736,7 +740,8 @@ def get_queryset(self): # Authorization: configuration -@extend_schema_view(**schema_with_prefetch()) +# @extend_schema_view(**schema_with_prefetch()) +# Nested models with prefetch make the response schema too long for Swagger UI class CredentialsMappingViewSet( PrefetchDojoModelViewSet, ): @@ -1473,7 +1478,8 @@ def get_queryset(self): # Authorization: object-based -@extend_schema_view(**schema_with_prefetch()) +# @extend_schema_view(**schema_with_prefetch()) +# Nested models with prefetch make the response schema too long for Swagger UI class JiraIssuesViewSet( PrefetchDojoModelViewSet, ): @@ -1589,7 +1595,8 @@ def get_queryset(self): # Authorization: object-based -@extend_schema_view(**schema_with_prefetch()) +# @extend_schema_view(**schema_with_prefetch()) +# Nested models with prefetch make the response schema too long for Swagger UI class DojoMetaViewSet( PrefetchDojoModelViewSet, ): @@ -1900,7 +1907,8 @@ def partial_update(self, request, pk=None): # Authorization: object-based -@extend_schema_view(**schema_with_prefetch()) +# @extend_schema_view(**schema_with_prefetch()) +# Nested models with prefetch make the response schema too long for Swagger UI class StubFindingsViewSet( PrefetchDojoModelViewSet, ): @@ -1938,7 +1946,8 @@ def get_queryset(self): # Authorization: object-based -@extend_schema_view(**schema_with_prefetch()) +# @extend_schema_view(**schema_with_prefetch()) +# Nested models with prefetch make the response schema too long for Swagger UI class TestsViewSet( PrefetchDojoModelViewSet, ra_api.AcceptedRisksMixin, @@ -2145,7 +2154,8 @@ def get_queryset(self): return Test_Type.objects.all().order_by("id") -@extend_schema_view(**schema_with_prefetch()) +# @extend_schema_view(**schema_with_prefetch()) +# Nested models with prefetch make the response schema too long for Swagger UI class TestImportViewSet( PrefetchDojoModelViewSet, ): diff --git a/dojo/forms.py b/dojo/forms.py index abd5a40d9ce..8c9b79ae029 100644 --- a/dojo/forms.py +++ b/dojo/forms.py @@ -2164,7 +2164,7 @@ def clean(self): class AddDojoUserForm(forms.ModelForm): email = forms.EmailField(required=True) password = forms.CharField(widget=forms.PasswordInput, - required=True, + required=settings.REQUIRE_PASSWORD_ON_USER, validators=[validate_password], help_text="") diff --git a/dojo/settings/.settings.dist.py.sha256sum b/dojo/settings/.settings.dist.py.sha256sum index 8a22d6140cf..2cd7ce83f4d 100644 --- a/dojo/settings/.settings.dist.py.sha256sum +++ b/dojo/settings/.settings.dist.py.sha256sum @@ -1 +1 @@ -bf2078296b31ba8c8376fdd88bbf1d552d0fba8b6e465a8552ac2fa901aa7e60 +64f33a0118941e6611212f08ee283befe7e7d5f8306f35280ccb6113817136dd diff --git a/dojo/settings/settings.dist.py b/dojo/settings/settings.dist.py index 826f5792b5c..7f63681cfe4 100644 --- a/dojo/settings/settings.dist.py +++ b/dojo/settings/settings.dist.py @@ -304,6 +304,8 @@ DD_QUALYS_LEGACY_SEVERITY_PARSING=(bool, True), # Use System notification settings to override user's notification settings DD_NOTIFICATIONS_SYSTEM_LEVEL_TRUMP=(list, ["user_mentioned", "review_requested"]), + # When enabled, force the password field to be required for creating/updating users + DD_REQUIRE_PASSWORD_ON_USER=(bool, True), ) @@ -527,6 +529,7 @@ def generate_url(scheme, double_slashes, user, password, host, port, path, param CLASSIC_AUTH_ENABLED = True FORGOT_PASSWORD = env("DD_FORGOT_PASSWORD") +REQUIRE_PASSWORD_ON_USER = env("DD_REQUIRE_PASSWORD_ON_USER") FORGOT_USERNAME = env("DD_FORGOT_USERNAME") PASSWORD_RESET_TIMEOUT = env("DD_PASSWORD_RESET_TIMEOUT") # Showing login form (form is not needed for external auth: OKTA, Google Auth, etc.) diff --git a/dojo/tools/awssecurityhub/inspector.py b/dojo/tools/awssecurityhub/inspector.py index 60c27e0b600..61b18be5bf8 100644 --- a/dojo/tools/awssecurityhub/inspector.py +++ b/dojo/tools/awssecurityhub/inspector.py @@ -12,7 +12,10 @@ def get_item(self, finding: dict, test): impact = [] references = [] unsaved_vulnerability_ids = [] - epss_score = None + if finding.get("EpssScore") is not None: + epss_score = finding.get("EpssScore") + else: + epss_score = None description = f"This is an Inspector Finding\n{finding.get('Description', '')}" + "\n" description += f"**AWS Finding ARN:** {finding_id}\n" description += f"**AwsAccountId:** {finding.get('AwsAccountId', '')}\n" diff --git a/helm/defectdojo/Chart.yaml b/helm/defectdojo/Chart.yaml index 1052b312093..7a0f65b8446 100644 --- a/helm/defectdojo/Chart.yaml +++ b/helm/defectdojo/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v2 appVersion: "2.39.0-dev" description: A Helm chart for Kubernetes to install DefectDojo name: defectdojo -version: 1.6.152-dev +version: 1.6.153-dev icon: https://www.defectdojo.org/img/favicon.ico maintainers: - name: madchap diff --git a/unittests/scans/awssecurityhub/issue_10956.json b/unittests/scans/awssecurityhub/issue_10956.json new file mode 100644 index 00000000000..d8a73cc33a1 --- /dev/null +++ b/unittests/scans/awssecurityhub/issue_10956.json @@ -0,0 +1,113 @@ +{ + "findings": [ + { + "EpssScore": "0.00239", + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:inspector2:us-east-1:1234567:finding/12344bc", + "ProductArn": "arn:aws:securityhub:us-east-1::product/aws/inspector", + "ProductName": "Inspector", + "CompanyName": "Amazon", + "Region": "us-east-1", + "GeneratorId": "AWSInspector", + "AwsAccountId": "1234567", + "Types": [ + "Software and Configuration Checks/Vulnerabilities/CVE" + ], + "FirstObservedAt": "2024-07-30T12:17:32.646Z", + "LastObservedAt": "2024-09-18T05:16:44.106Z", + "CreatedAt": "2024-07-30T12:17:32.646Z", + "UpdatedAt": "2024-09-18T05:16:44.106Z", + "Severity": { + "Label": "MEDIUM", + "Normalized": 50 + }, + "Title": "CVE-2024-123 - fdd", + "Description": "A vulnerability was found in sdd.", + "Remediation": { + "Recommendation": { + "Text": "None Provided" + } + }, + "ProductFields": { + "aws/inspector/FindingStatus": "ACTIVE", + "aws/inspector/inspectorScore": "5.1", + "aws/inspector/resources/1/resourceDetails/awsEc2InstanceDetails/platform": "AMAZON_LINUX_2023", + "aws/inspector/ProductVersion": "1", + "aws/inspector/instanceId": "i-1234xxyy", + "aws/securityhub/FindingId": "arn:aws:inspector2:us-east-1:1234567:finding/addfss", + "aws/securityhub/ProductName": "Inspector", + "aws/securityhub/CompanyName": "Amazon" + }, + "Resources": [ + { + "Type": "AwsEc2Instance", + "Id": "i-1234xxyy", + "Partition": "aws", + "Region": "us-east-1", + "Tags": { + "Name": "Name:xx-123-yy" + }, + "Details": { + "AwsEc2Instance": { + "Type": "tt", + "ImageId": "ami-1234", + "IpV4Addresses": [ + "0.0.0.0" + ], + "IamInstanceProfileArn": "arn:aws:iam::1234567:instance-profile/something", + "VpcId": "vpc-1234", + "SubnetId": "subnet-xxxxxxx", + "LaunchedAt": "2024-09-18T05:16:44.106Z" + } + } + } + ], + "WorkflowState": "NEW", + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE", + "Vulnerabilities": [ + { + "Id": "CVE-2024-1234", + "VulnerablePackages": [ + { + "Name": "aa", + "Version": "1.2.0", + "Architecture": "X86_64]", + "PackageManager": "OS", + "FixedInVersion": "abc[2.0]" + } + ], + "Cvss": [ + { + "Version": "3.1", + "BaseScore": "7.5", + "BaseVector": "CVSS:9.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", + "Source": "NVD" + } + ], + "Vendor": { + "Name": "AMAZON_CVE", + "Url": "https://alas.aws.amazon.com/cve/json/v1/CVE-2024-1234.json", + "VendorSeverity": "Medium", + "VendorCreatedAt": "2024-01-16T00:00:00Z", + "VendorUpdatedAt": "2024-09-18T05:16:44.106Z" + }, + "ReferenceUrls": [ + "https://alas.aws.amazon.com" + ], + "FixAvailable": "YES" + } + ], + "FindingProviderFields": { + "Severity": { + "Label": "MEDIUM" + }, + "Types": [ + "Software and Configuration Checks/Vulnerabilities/CVE" + ] + } + } + ] + } \ No newline at end of file diff --git a/unittests/tools/test_awssecurityhub_parser.py b/unittests/tools/test_awssecurityhub_parser.py index 14e53d3cce7..9d05083eaff 100644 --- a/unittests/tools/test_awssecurityhub_parser.py +++ b/unittests/tools/test_awssecurityhub_parser.py @@ -126,3 +126,11 @@ def test_guardduty(self): endpoint = findings[0].unsaved_endpoints[0] self.assertEqual("AwsEc2Instance arn:aws:ec2:us-east-1:123456789012:instance/i-1234567890", endpoint.host) self.assertEqual("This is a GuardDuty Finding\nAPIs commonly used in Discovery tactics were invoked by user AssumedRole : 123123123, under anomalous circumstances. Such activity is not typically seen from this user.\n**AWS Finding ARN:** arn:aws:guardduty:us-east-1:123456789012:detector/123456789/finding/2123123123123\n**SourceURL:** [https://us-east-1.console.aws.amazon.com/guardduty/home?region=us-east-1#/findings?macros=current&fId=2123123123123](https://us-east-1.console.aws.amazon.com/guardduty/home?region=us-east-1#/findings?macros=current&fId=2123123123123)\n**AwsAccountId:** 123456789012\n**Region:** us-east-1\n**Generator ID:** arn:aws:guardduty:us-east-1:123456789012:detector/123456789\n", finding.description) + + def test_issue_10956(self): + with open(get_unit_tests_path() + sample_path("issue_10956.json"), encoding="utf-8") as test_file: + parser = AwsSecurityHubParser() + findings = parser.get_findings(test_file, Test()) + self.assertEqual(1, len(findings)) + finding = findings[0] + self.assertEqual("0.00239", finding.epss_score)