Add support to restrict @Core.AcceptableMediaTypes#732
Add support to restrict @Core.AcceptableMediaTypes#732samyuktaprabhu wants to merge 7 commits intomainfrom
Conversation
There was a problem hiding this comment.
The PR adds media type restriction support for attachments. I've identified a few issues: a typo in MIME type definitions (application/txt should be text/plain), potential security concerns with filename validation (missing path traversal checks), and a minor note about null handling. Overall the implementation is reasonable but needs these corrections before merging.
PR Bot Information
Version: 1.17.53 | 📖 Documentation | 🚨 Create Incident | 💬 Feedback
- Event Trigger:
pull_request.opened - LLM:
anthropic--claude-4.5-sonnet - Correlation ID:
78c854a0-0757-11f1-833c-299ee35f3dc8
...ap/cds/feature/attachments/handler/applicationservice/helper/AttachmentValidationHelper.java
Outdated
Show resolved
Hide resolved
...s/src/main/java/com/sap/cds/feature/attachments/handler/common/ApplicationHandlerHelper.java
Outdated
Show resolved
Hide resolved
...ap/cds/feature/attachments/handler/applicationservice/helper/AttachmentValidationHelper.java
Outdated
Show resolved
Hide resolved
8b6c095 to
a12bc05
Compare
There was a problem hiding this comment.
Summary
The pull request introduces MIME type validation for attachments with good test coverage. However, several null safety issues were identified in the validation logic that could lead to NullPointerException errors. Additionally, a minor CDS syntax inconsistency and a misleading test variable name should be addressed.
PR Bot Information
Version: 1.17.61 | 📖 Documentation | 🚨 Create Incident | 💬 Feedback
- Event Trigger:
issue_comment.created - Correlation ID:
b7b79080-0bdb-11f1-9b97-78cdc3653ab1 - LLM:
anthropic--claude-4.5-sonnet
...ap/cds/feature/attachments/handler/applicationservice/helper/AttachmentValidationHelper.java
Outdated
Show resolved
Hide resolved
...ap/cds/feature/attachments/handler/applicationservice/helper/AttachmentValidationHelper.java
Show resolved
Hide resolved
...s/src/main/java/com/sap/cds/feature/attachments/handler/common/ApplicationHandlerHelper.java
Outdated
Show resolved
Hide resolved
...ture/attachments/integrationtests/nondraftservice/MediaValidatedAttachmentsNonDraftTest.java
Outdated
Show resolved
Hide resolved
e2b000e to
26b499c
Compare
There was a problem hiding this comment.
Unit-Tests:
- AttachmentCalidationHelperTest:
- Add a test for wildcard subtype rejection like
image/*should rejectapplication/pdf - Add a test for files start with
.like.gitignoreor.sshor.zshrcand so on
- Add a test for wildcard subtype rejection like
Integration-Tests:
- MediaCalidatedAttachmentsDraftTest:
- Add a test for false inputs like an empty string. You have them for non draft but not for draft.
- Add tests for situations where it fails like upload a
pdfwhen onlyjpegorimage/*is allowed- Also one for dotfiles
- MediaValidatedAttachmentsNonDraftTest:
- Add a test for case sensitivity in the extension
- Add a test for no extension
- Add a test for hidden files again
...ap/cds/feature/attachments/handler/applicationservice/helper/AttachmentValidationHelper.java
Outdated
Show resolved
Hide resolved
...ds/feature/attachments/handler/applicationservice/helper/AttachmentValidationHelperTest.java
Outdated
Show resolved
Hide resolved
...ds/feature/attachments/integrationtests/draftservice/MediaValidatedAttachmentsDraftTest.java
Outdated
Show resolved
Hide resolved
3df6d49 to
e98f840
Compare
There was a problem hiding this comment.
Summary
This PR introduces MIME type validation for attachments with generally solid implementation. I've identified 9 substantive issues requiring attention:
- Critical: Missing file extension validation in
MediaTypeService.resolveMimeType()could cause runtime errors - Important: Inconsistent filename validation between extractor and validator creates confusing error paths
- Security consideration:
FileNameValidatordoesn't check for path traversal characters (e.g.,../, null bytes) - Several performance and code quality improvements around duplicate constants, inefficient stream operations, and wildcard matching logic
The test coverage is comprehensive, and the feature design is well-thought-out. Address the validation and error-handling gaps before merging.
PR Bot Information
Version: 1.17.72 | 📖 Documentation | 🚨 Create Incident | 💬 Feedback
- LLM:
anthropic--claude-4.5-sonnet - Event Trigger:
issue_comment.created - Correlation ID:
a7941f80-1242-11f1-91ae-db28216a7610
...om/sap/cds/feature/attachments/handler/applicationservice/helper/media/MediaTypeService.java
Outdated
Show resolved
Hide resolved
...om/sap/cds/feature/attachments/handler/applicationservice/helper/media/MediaTypeService.java
Show resolved
Hide resolved
...om/sap/cds/feature/attachments/handler/applicationservice/helper/media/MediaTypeService.java
Outdated
Show resolved
Hide resolved
...chments/handler/applicationservice/helper/mimeTypeValidation/AttachmentValidationHelper.java
Show resolved
Hide resolved
...m/sap/cds/feature/attachments/handler/applicationservice/helper/AttachmentDataExtractor.java
Outdated
Show resolved
Hide resolved
...m/sap/cds/feature/attachments/handler/applicationservice/helper/AttachmentDataExtractor.java
Show resolved
Hide resolved
.../cds/feature/attachments/handler/applicationservice/helper/validation/FileNameValidator.java
Outdated
Show resolved
Hide resolved
...ava/com/sap/cds/feature/attachments/handler/applicationservice/CreateAttachmentsHandler.java
Show resolved
Hide resolved
...s/src/main/java/com/sap/cds/feature/attachments/handler/common/ApplicationHandlerHelper.java
Outdated
Show resolved
Hide resolved
Schmarvinius
left a comment
There was a problem hiding this comment.
I think your whole structe has gotten very complicated.
Why don't you merge FileNameValidator + MediaTypeService + MediaTypeResolver + AttachmentValidationHelper into one MediaTypeValidator
And keep the DataExtractor as-is. This reduces complexity and keeps separation of concern to a healthy degree.
...re-attachments/src/main/java/com/sap/cds/feature/attachments/configuration/Registration.java
Outdated
Show resolved
Hide resolved
...re-attachments/src/main/java/com/sap/cds/feature/attachments/configuration/Registration.java
Outdated
Show resolved
Hide resolved
...re-attachments/src/main/java/com/sap/cds/feature/attachments/configuration/Registration.java
Show resolved
Hide resolved
...re-attachments/src/main/java/com/sap/cds/feature/attachments/configuration/Registration.java
Outdated
Show resolved
Hide resolved
...om/sap/cds/feature/attachments/handler/applicationservice/helper/media/MediaTypeService.java
Outdated
Show resolved
Hide resolved
...ure/attachments/handler/applicationservice/helper/validation/AttachmentValidationHelper.java
Outdated
Show resolved
Hide resolved
...ure/attachments/handler/applicationservice/helper/validation/AttachmentValidationHelper.java
Outdated
Show resolved
Hide resolved
...ure/attachments/handler/applicationservice/helper/validation/AttachmentValidationHelper.java
Show resolved
Hide resolved
...ure/attachments/handler/applicationservice/helper/validation/AttachmentValidationHelper.java
Outdated
Show resolved
Hide resolved
...m/sap/cds/feature/attachments/handler/applicationservice/helper/AttachmentDataExtractor.java
Outdated
Show resolved
Hide resolved
Thanks for your review &suggestion. I merged FileNameValidator & AttachmentDataExtractor. I tried doing the merge for the other 3 files, but, if we do that, we'd end up making it harder to test, and also make it harder to reuse later. |
534423e to
ab8ab07
Compare
…chments/configuration/Registration.java Co-authored-by: Marvin <marvin.lindner@sap.com> Update cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/configuration/Registration.java Co-authored-by: Marvin <marvin.lindner@sap.com> Update cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/configuration/Registration.java Co-authored-by: Marvin <marvin.lindner@sap.com> Update cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/configuration/Registration.java Co-authored-by: Marvin <marvin.lindner@sap.com> apply mvnspotless:apply Rename AttachmentDataExtractor to validation package Refactor MediaTypeService to use URLConnection for MIME type resolution and update AttachmentValidationHelper method visibility Refactor AttachmentValidationHelper to streamline MIME type validation logic Add unit tests for AssociationCascader and refactor AttachmentValidationHelper and MediaTypeResolver to utilize AssociationCascader for media entity resolution Refactor MediaTypeResolver to remove dependency on ApplicationHandlerHelper and update related tests Refactor file name validation logic and migrate to mimeTypeValidation package Refactor AttachmentDataExtractor to integrate filename validation logic and remove FileNameValidator class Refactor AttachmentDataExtractor and update tests to improve structure and maintainability Refactor AttachmentValidationHelper and MediaTypeResolver to improve structure and add unit tests for media type resolution revert a change
46592c3 to
c458640
Compare
| }); | ||
| } | ||
|
|
||
| private static String fallbackToDefaultMimeType(String fileName) { |
There was a problem hiding this comment.
Why is an extra function needed?
| if (acceptableMediaTypes == null | ||
| || acceptableMediaTypes.isEmpty() | ||
| || acceptableMediaTypes.contains("*/*")) return true; |
There was a problem hiding this comment.
| if (acceptableMediaTypes == null | |
| || acceptableMediaTypes.isEmpty() | |
| || acceptableMediaTypes.contains("*/*")) return true; | |
| if (acceptableMediaTypes == null || acceptableMediaTypes.isEmpty()) { | |
| return true; | |
| } | |
| if (acceptableMediaTypes.stream().anyMatch(type -> type.trim().toLowerCase().equals("*/*"))) { | |
| return true; | |
| } |
There was a problem hiding this comment.
The contains("/") check runs on the raw annotation values before normalization (trim().toLowerCase()), so a value like " / " with surrounding whitespace would fail to short-circuit as a wildcard. Consider normalizing first, or moving this check after normalization.
| boolean areAttachmentsAvailable = | ||
| ApplicationHandlerHelper.isMediaEntity(entity) | ||
| || cascader.hasAttachmentPath(cdsModel, entity); | ||
|
|
||
| if (!areAttachmentsAvailable) { | ||
| return; | ||
| } | ||
|
|
||
| // validate the media types of the attachments | ||
| Map<String, List<String>> allowedTypesByElementName = | ||
| MediaTypeResolver.getAcceptableMediaTypesFromEntity(entity, cdsModel); | ||
| Map<String, Set<String>> fileNamesByElementName = | ||
| AttachmentDataExtractor.extractAndValidateFileNamesByElement(entity, data); |
There was a problem hiding this comment.
hasAttachmentPath and findMediaEntityNames both internally call findEntityPath, so the entity tree is traversed twice per request. You could avoid this by calling findMediaEntityNames once and using its result to determine both conditions
| private static String validateAndNormalize(String fileName) { | ||
| String trimmedFileName = fileName.trim(); | ||
| if (trimmedFileName.isEmpty()) { | ||
| throw new ServiceException(ErrorStatuses.BAD_REQUEST, "Filename must not be blank"); | ||
| } | ||
|
|
||
| int lastDotIndex = trimmedFileName.lastIndexOf('.'); | ||
| if (lastDotIndex == -1 || lastDotIndex == trimmedFileName.length() - 1) { | ||
| throw new ServiceException(ErrorStatuses.BAD_REQUEST, "Invalid filename format: " + fileName); | ||
| } | ||
| return trimmedFileName; | ||
| } |
There was a problem hiding this comment.
validateAndNormalize throws BAD_REQUEST when a filename has no extension, while MediaTypeService.resolveMimeType handles the same case by falling back to a default MIME type (application/octet-stream). Since validateAndNormalize runs first in the flow, the fallback in resolveMimeType is unreachable for this code path.
Add Support to Restrict @Core.AcceptableMediaTypes
✨ New Features
Introduced support for restricting allowed MIME types for attachments using the
@Core.AcceptableMediaTypesannotation. This feature enables validation of file types during upload atHandlerOrder.BEFORE, ensuring only specified media types are accepted before processing begins.🔧 Changes
Core Implementation
CreateAttachmentsHandler.java: Added new@Beforehandler methodprocessBeforeForMetadatathat validates acceptable media types early in the request lifecycle. Updated constructor to acceptCdsRuntimeparameter for metadata validation support.AttachmentValidationHelper.java(new): Comprehensive helper class for media type validation with support for wildcard patterns (image/*) and default fallback behavior (*/*). Validates file types against configured acceptable media types.MediaTypeResolver.java(new): Extracts acceptable media types from CDS entity annotations, handling both direct media entities and composed attachments using theAssociationCascader.MediaTypeService.java(new): Provides MIME type resolution from file extensions using Java'sURLConnection.getFileNameMap()and validates against acceptable media types with support for exact matches and wildcard patterns.AttachmentDataExtractor.java(new): Extracts and validates file names from attachment data usingCdsDataProcessor, ensuring files have proper extensions before MIME type validation.Registration.java: Updated handler registration to passCdsRuntimeinstance toCreateAttachmentsHandler.ApplicationHandlerHelper.java: AddeddeepSearchForAttachments()method functionality (refactored intoAssociationCascader).AssociationCascader.java: Enhanced withhasAttachmentPath()andfindMediaEntityNames()methods to recursively check for attachment compositions in entity hierarchies and collect media entity names.Documentation
README.md: Added comprehensive documentation section "Restrict allowed MIME types" with examples of:image/jpeg,image/png)image/*)*/*)Test Suite
CreateAttachmentsHandlerTest.java: Added tests for new metadata validation handler with proper annotation verificationAttachmentValidationHelperTest.java(new): Comprehensive test suite with 16+ test cases covering MIME type detection, validation, wildcards, error scenarios, and edge cases including hidden filesMediaTypeResolverTest.java(new): Tests for media type extraction from entity annotationsMediaTypeServiceTest.java(new): Tests for MIME type resolution and validation logic including edge cases like hidden files (.gitignore)MediaValidatedAttachmentsDraftTest.java(new): Integration tests for draft service media validation with parameterized tests for various file typesMediaValidatedAttachmentsNonDraftTest.java(new): Integration tests for non-draft service media validation, including deep create scenarios and multiple attachment validationAssociationCascaderTest.java: Added tests for newhasAttachmentPath()andfindMediaEntityNames()methodsSize validation tests: Updated to include
fileNameassignments for proper validationIntegration Test Configuration
data-model.cds: AddedmediaValidatedAttachmentsandmimeValidatedAttachmentscompositions to Roots entitytest-service.cds: Configured annotations to accept only JPEG and PNG images formediaValidatedAttachments, and PDFs formimeValidatedAttachmentsRootEntityBuilder.java: Enhanced builder to initializesizeLimitedAttachmentslist in constructor for proper entity setupSample Application
samples/bookshop/srv/attachments.cds:mediaValidatedAttachmentscomposition to Books entity📬 Subscribe to the Hyperspace PR Bot DL to get the latest announcements and pilot features!
PR Bot Information
Version:
1.17.80| 📖 Documentation | 🚨 Create Incident | 💬 Feedbackanthropic--claude-4.5-sonnetpull_request.edited27d010e0-1609-11f1-9c18-5f2e249083ea