Skip to content

fix: cache items only when coming from trusted proxy#4651

Open
achmelo wants to merge 42 commits into
v3.x.xfrom
reboot/cache-key
Open

fix: cache items only when coming from trusted proxy#4651
achmelo wants to merge 42 commits into
v3.x.xfrom
reboot/cache-key

Conversation

@achmelo
Copy link
Copy Markdown
Member

@achmelo achmelo commented May 28, 2026

Description

Caching service allows to store items under the arbitrary value in header if the request is authenticated with client certificate. This change makes the validation more strict and allow to items only when the request is coming from a trusted proxy. It also drops support for custom header and keeps only standard Client-Cert header.

Linked to # (issue)
Part of the # (epic)

Type of change

Please delete options that are not relevant.

  • fix: Bug fix (non-breaking change which fixes an issue)
  • feat: New feature (non-breaking change which adds functionality)
  • docs: Change in a documentation
  • refactor: Refactor the code
  • chore: Chore, repository cleanup, updates the dependencies.
  • BREAKING CHANGE or !: Breaking change (fix or feature that would cause existing functionality to not work as expected)

Checklist:

  • My code follows the style guidelines of this project
  • PR title conforms to commit message guideline ## Commit Message Structure Guideline
  • I have commented my code, particularly in hard-to-understand areas. In JS I did provide JSDoc
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • The java tests in the area I was working on leverage @nested annotations
  • Any dependent changes have been merged and published in downstream modules

For more details about how should the code look like read the Contributing guideline

achmelo added 21 commits May 27, 2026 08:59
Signed-off-by: ac892247 <a.chmelo@gmail.com>
Signed-off-by: ac892247 <a.chmelo@gmail.com>
…in config

Signed-off-by: ac892247 <a.chmelo@gmail.com>
Signed-off-by: ac892247 <a.chmelo@gmail.com>
Signed-off-by: ac892247 <a.chmelo@gmail.com>
Signed-off-by: ac892247 <a.chmelo@gmail.com>
Signed-off-by: ac892247 <a.chmelo@gmail.com>
Signed-off-by: ac892247 <a.chmelo@gmail.com>
Signed-off-by: ac892247 <a.chmelo@gmail.com>
Signed-off-by: ac892247 <a.chmelo@gmail.com>
# Conflicts:
#	caching-service-package/src/main/resources/bin/start.sh
#	caching-service/src/test/java/org/zowe/apiml/caching/config/SecurityConfigTest.java
Signed-off-by: ac892247 <a.chmelo@gmail.com>
Signed-off-by: ac892247 <a.chmelo@gmail.com>
Signed-off-by: ac892247 <a.chmelo@gmail.com>
…lient certificate was provided

Signed-off-by: ac892247 <a.chmelo@gmail.com>
Signed-off-by: ac892247 <a.chmelo@gmail.com>
Signed-off-by: ac892247 <a.chmelo@gmail.com>
Signed-off-by: ac892247 <a.chmelo@gmail.com>
Signed-off-by: ac892247 <a.chmelo@gmail.com>
Signed-off-by: ac892247 <a.chmelo@gmail.com>
achmelo and others added 5 commits May 28, 2026 15:36
Signed-off-by: ac892247 <a.chmelo@gmail.com>
Signed-off-by: ac892247 <a.chmelo@gmail.com>
Signed-off-by: ac892247 <a.chmelo@gmail.com>
Comment on lines +96 to +97
log.debug("DEBUG: isForwardingEnabled = {}", certificateValidator.isForwardingEnabled());
log.debug("DEBUG: hasGatewayChain = {}", certificateValidator.hasGatewayChain(certsFromTls));
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.

These messge don't make sense here. They should be before the if (here it is clear what is the value) and also evaluate the same code is not needed.

);

logIgnoredCertificates(new X509Certificate[]{clientCertFromHeader.get()}, clientAuthCerts);
log.debug("DEBUG: clientAuthCerts.length = {}", clientAuthCerts.length);
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.

I would say for debugging an issue it would be helpfull to write some information about certificates. Not necessary the whole key, but serial number for example.

Comment thread .github/workflows/integration-tests.yml Outdated
caching-service:
image: ghcr.io/balhar-jakub/caching-service:${{ github.run_id }}-${{ github.run_number }}
env:
APIML_SECURITY_X509_ACCEPTFORWARDEDCERT: true
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.

This value is in application.yaml. It is not needed to set again. Btw. I guess the URL of cert should be detected by CS automatically.

private static final String VALID_BASIC_AUTH = "Basic " + Base64.getEncoder().encodeToString((USER + ":" + PASSWORD).getBytes());
private static final String INVALID_BASIC_AUTH = "Basic " + Base64.getEncoder().encodeToString((USER + ":invalidPassword").getBytes());
private static final String X_CS_SERVICE_ID = "X-CS-Service-ID";
private static final String X_CS_SERVICE_ID = "Client-Cert";
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.

field X_CS_SERVICE_ID is unclear

-Dapiml.service.ssl.trust-store="${client_truststore_location}" \
-Dapiml.service.ssl.trust-store-password="${client_truststore_pass}" \
-Dapiml.service.ssl.trust-store-type="${client_truststore_type}" \
-Dapiml.security.x509.acceptForwardedCert=${ZWE_configs_apiml_security_x509_enabled:-${ZWE_components_gateway_apiml_security_x509_enabled:-true}} \
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.

Regarding these changes does it make sense have certificate forwarding configurable

achmelo added 12 commits June 1, 2026 10:32
Signed-off-by: ac892247 <a.chmelo@gmail.com>
Signed-off-by: ac892247 <a.chmelo@gmail.com>
Signed-off-by: ac892247 <a.chmelo@gmail.com>
Signed-off-by: ac892247 <a.chmelo@gmail.com>
Signed-off-by: ac892247 <a.chmelo@gmail.com>
Signed-off-by: ac892247 <a.chmelo@gmail.com>
Signed-off-by: ac892247 <a.chmelo@gmail.com>
Signed-off-by: ac892247 <a.chmelo@gmail.com>
Signed-off-by: ac892247 <a.chmelo@gmail.com>
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

@pavel-jares-bcm pavel-jares-bcm left a comment

Choose a reason for hiding this comment

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

Please take a look also on Sonar issues.

hostname: caching-service
banner: console

security:
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.

All configuration should be updated, including local config

VPx2
""".replaceAll("\\s+", "");

@org.junit.jupiter.api.BeforeEach
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.

Suggested change
@org.junit.jupiter.api.BeforeEach
@BeforeEach
  • import org.junit.jupiter.api.BeforeEach

enabled: true
security:
x509:
certificatesUrl: https://localhost:10010/gateway/certificates
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.

Shouldn't we prefer the full URL (https://localhost:10010/gateway/api/v1/certificates). Both of them are supported, but I would say the i'm should be use the one with API version.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

this is only for local run, in start.sh it uses the same URL as zaas service

certificateValidator.hasGatewayChain(certsFromTls)) {
Optional<X509Certificate> clientCertFromHeader = getClientCertFromHeader(exchange.getRequest());
log.debug("clientCertFromHeader.isPresent = {}", clientCertFromHeader.isPresent());
if (clientCertFromHeader.isPresent()) {
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.

The logic was changed, when the request is signed by Zowe certificate and there is no client cert header certificates are not logged and no attibute is set. I would say, the original implementation is better. We should process that in the else statement. It has probably no impact to caching service, but the behaviour could be different for internal API. Basically, I guess it just could make debugging of an issue more complicated.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

the only thing that changed is a log message, what exactly is wrong about it?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

now I got, it's moved back to original condition

void whenNoBasicAuth_thenReturnForbidden() {
given()
.header(new Header(X_CS_SERVICE_ID, "apimtst"))
.header(new Header(CLIENT_CERT_HEADER_NAME, MOCK_FORWARDED_CERT))
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.

Do we have somewhere test with clientCert and service prefix?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

InMemoryFunctionalTest

achmelo and others added 4 commits June 2, 2026 09:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Sensitive Sensitive change that requires peer review size/XL

Projects

Development

Successfully merging this pull request may close these issues.

2 participants