Skip to content

feat(core)!: ingestion security processor - #123

Draft
foukou19 wants to merge 44 commits into
mainfrom
feat/ingestion-security-processor
Draft

feat(core)!: ingestion security processor#123
foukou19 wants to merge 44 commits into
mainfrom
feat/ingestion-security-processor

Conversation

@foukou19

Copy link
Copy Markdown
Collaborator

PR Description

What this PR Provides

  • Describe in short sentences the goal of the PR. Use lists.
  • If the PR is linked to an ADR, please provide the link.

Fixes

Review

The reviewer must double-check these points:

  • The reviewer has tested the feature
  • The reviewer has reviewed the implementation of the feature
  • The documentation has been updated
  • The feature implementation respects the Technical Doc / ADR previously produced
  • The Pull Request title has a ! after the type/scope to identify the breaking
    change in the release note and ensure we will release a major version.

How to test

Please refer (copy/paste) the test section from the User Story. This should include

  • The initial state: what should be the status of the system before testing
    (for example, ensure the data xxx exists in idp-back to be able to test the feature)
  • What and how to test: steps to perform to test the feature
    (for example, go to page xxx, fill the xxx field and click the 'send' button)
  • Expected results: what should be observed for success or failure
    (for example, there is a link in the database between component X and component Y.
    You can retrieve the information with a GET request to the API)

Breaking changes (if any)

  • Data loss / modification
  • API JSON schema modification (existing resource / behavior)
  • Behavior modification of a component
  • Others
  • N/A

Context of the Breaking Change

For example: we redefined the component types list in the DPAC referential

Result of the Breaking Change

For example: your component of type xxx will migrate to the type yyy

foukou19 and others added 20 commits July 21, 2026 13:24
…object and array payloads

Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
@foukou19
foukou19 marked this pull request as draft August 12, 2026 14:12
Signed-off-by: ferial OUKOUKAS <75682459+foukou19@users.noreply.github.com>
@github-code-quality

github-code-quality Bot commented Aug 12, 2026

Copy link
Copy Markdown

Code Coverage Overview

Languages: Java

Java / code-coverage/jacoco

The overall line coverage in commit 55ca6d9 in the feat/ingestion-secur... branch remains at 90%, unchanged from commit f148be0 in the main branch.

Show a line coverage summary of the most impacted files.
File main f148be0 feat/ingestion-secur... 55ca6d9 +/-
com/decathlon/i...yValidator.java 100% 86% -14%
com/decathlon/i...yValidator.java 100% 94% -6%
com/decathlon/i...uteBuilder.java 100% 96% -4%
com/decathlon/i...yValidator.java 86% 88% +2%
com/decathlon/i...dlerHelper.java 94% 97% +3%
com/decathlon/i...ationUtils.java 82% 87% +5%
com/decathlon/i...yProcessor.java 67% 86% +19%
com/decathlon/i...nException.java 0% 50% +50%
com/decathlon/i...erProvider.java 33% 100% +67%
com/decathlon/i...dException.java 0% 100% +100%

Updated August 21, 2026 15:47 UTC

Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
…error responses

Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
@foukou19
foukou19 force-pushed the feat/ingestion-security-processor branch from 3b6ec83 to d276814 Compare August 13, 2026 14:01
@foukou19
foukou19 requested a balanced review from Copilot August 14, 2026 14:54
brandPittCode and others added 13 commits August 17, 2026 11:32
Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
…error responses

Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
Signed-off-by: ferial OUKOUKAS <75682459+foukou19@users.noreply.github.com>
@foukou19 foukou19 changed the title Feat/ingestion security processor feat(core)!: ingestion security processor Aug 17, 2026
Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
@foukou19
foukou19 force-pushed the feat/ingestion-security-processor branch from 59523a8 to 1e9f829 Compare August 19, 2026 13:33
@foukou19
foukou19 force-pushed the feat/ingestion-security-processor branch 4 times, most recently from ef960c1 to 346711c Compare August 21, 2026 13:11
Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
@foukou19
foukou19 force-pushed the feat/ingestion-security-processor branch 2 times, most recently from 143b0a3 to c06eb85 Compare August 21, 2026 14:09
@foukou19
foukou19 requested a balanced review from Copilot August 21, 2026 14:37

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 23 out of 24 changed files in this pull request and generated 2 comments.

Suppressed comments (8)

src/main/java/com/decathlon/idp_core/domain/port/WebhookSecurityStrategy.java:41

  • The Domain port now defines an HTTP-header contract and names Infrastructure exceptions/status semantics. This reverses the required dependency direction: the Domain layer must not know about HTTP or Infrastructure. Keep creation-time domain validation on a domain port, and move runtime request authentication to an Infrastructure-owned strategy contract with adapter exceptions mapped by the ingestion route.
  /// Validates an incoming webhook request at runtime.
  ///
  /// @param headers the inbound HTTP headers
  /// @param rawPayload the exact inbound payload bytes (before decoding)
  /// @param config the persisted security configuration
  /// @throws
  /// com.decathlon.idp_core.infrastructure.adapters.ingestion.exception.WebhookAuthUnauthorizedException
  /// when authentication is missing or malformed (401)
  /// @throws
  /// com.decathlon.idp_core.infrastructure.adapters.ingestion.exception.WebhookAuthForbiddenException
  /// when authentication is provided but rejected (403)
  void validateRequest(Map<String, Object> headers, byte[] rawPayload, Map<String, String> config);

src/main/java/com/decathlon/idp_core/infrastructure/adapters/webhook/security/JwtBearerSecurityValidator.java:146

  • expectedAudience is silently ignored, although the security configuration contract supports camelCase variants. A caller using that spelling gets no audience validation at all. Resolve both spellings as is already done for the other JWT keys.
  private String resolveOptionalExpectedAudience(Map<String, String> config) {
    return config.get(KEY_EXPECTED_AUDIENCE_SNAKE_CASE);

src/main/java/com/decathlon/idp_core/infrastructure/adapters/webhook/security/JwtBearerSecurityValidator.java:130

  • Audience validation is skipped when expected_audience is absent, and the provider's JwtValidators.createDefault() only performs default timestamp-style validation. This accepts a valid token issued for a different recipient whenever its identity claim is allow-listed, enabling cross-service token replay. Require/derive the webhook audience and always validate aud.
    if (StringUtils.hasText(optionalExpectedAudience)) {
      validateAudienceClaim(jwt, optionalExpectedAudience);
    }

src/main/java/com/decathlon/idp_core/infrastructure/adapters/webhook/security/BasicAuthSecurityValidator.java:54

  • HTTP authentication scheme names are case-insensitive, but this rejects valid basic/mixed-case schemes. Use a case-insensitive prefix comparison while retaining the current credential extraction.
    if (!authorization.startsWith("Basic ")) {

src/main/java/com/decathlon/idp_core/infrastructure/adapters/webhook/security/JwtBearerSecurityValidator.java:109

  • HTTP authentication scheme names are case-insensitive, but this rejects otherwise valid bearer/mixed-case authorization headers. Compare the scheme case-insensitively.
    if (!authorization.startsWith(BEARER_PREFIX)
        || authorization.substring(BEARER_PREFIX.length()).isBlank()) {

src/main/java/com/decathlon/idp_core/infrastructure/adapters/webhook/security/JwtBearerSecurityValidator.java:65

  • These new mandatory JWT keys are absent from the public webhook documentation: docs/src/concepts/webhooks.md:113-119 still says JWT requires only jwks_uri, and its example at lines 165-174 now produces a 400 response. Update the documentation and example with client_id_field, client_id_values, and the audience contract.
    String clientIdValues = WebhookSecurityConfigurationUtils.required(config,
        KEY_CLIENT_ID_VALUES_SNAKE_CASE, KEY_CLIENT_ID_VALUES_CAMEL_CASE);

src/main/java/com/decathlon/idp_core/infrastructure/adapters/ingestion/exception_handler/WebhookErrorCode.java:18

  • This error is also used for unsupported encodings and decompression-size violations, so reporting every failure as “invalid or corrupted” is inaccurate and hides the actionable cause. Preserve a description covering invalid, unsupported, and oversized payloads (or safely expose each WebhookDecodingException message).
  INVALID_COMPRESSED_PAYLOAD("invalid_compressed_payload", HttpStatus.BAD_REQUEST,
      LoggingLevel.WARN, "Invalid or corrupted compressed payload"),

src/test/java/com/decathlon/idp_core/infrastructure/adapters/ingestion/InboundWebhookIngestionRouteTest.java:360

  • This test can pass on an authentication failure: Camel's handled exception route clears exchange.getException() and instead writes a 401 response. Moreover, the production provider constructs its own Nimbus decoder (WebhookJwtDecoderProvider.java:17-23), so the test's primary JwtDecoder mock is unused and this fake token causes a real request to auth.example.com. Mock the provider/decoder and assert that no authentication error response was produced.
    Exchange exchange = invokeValidateSecurityRoute(connector,
        Map.of("Authorization", "Bearer " + token));

    assertNull(exchange.getException());

@Override
public void validateConfiguration(Map<String, String> config) {
WebhookSecurityConfigurationUtils.required(config, "username");
WebhookSecurityConfigurationUtils.required(config, USERNAME_KEY);
Comment on lines +47 to 50
String jwksUriValue = WebhookSecurityConfigurationUtils.required(config,
KEY_JWKS_URI_SNAKE_CASE, KEY_JWKS_URI_CAMEL_CASE);
if (jwksUriValue.isBlank()) {
throw new WebhookSecurityConfigurationException("Invalid jwks_uri for JWT_BEARER security");
Signed-off-by: foukou19 <ferial.oukoukas@decathlon.com>
@foukou19
foukou19 force-pushed the feat/ingestion-security-processor branch from c06eb85 to 55ca6d9 Compare August 21, 2026 15:43
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants