Andrea Cosentino created CAMEL-24429:
----------------------------------------
Summary: camel-as2 - per-request security material outlives the
request in ResponseMDN and the listener context
Key: CAMEL-24429
URL: https://issues.apache.org/jira/browse/CAMEL-24429
Project: Camel
Issue Type: Bug
Components: camel-as2
Reporter: Andrea Cosentino
Assignee: Andrea Cosentino
Fix For: 4.23.0
Two places keep per-request state where it can be observed by a later or
concurrent request.
*ResponseMDN* holds the security material in mutable instance fields and
overwrites them per request:
{code:java}
private AS2SignatureAlgorithm signingAlgorithm;
private Certificate[] signingCertificateChain;
private PrivateKey signingPrivateKey;
private PrivateKey decryptingPrivateKey;
private Certificate[] validateSigningCertificateChain;
private boolean keysAreDynamic = false;
...
if (this.keysAreDynamic) {
this.signingAlgorithm = (AS2SignatureAlgorithm)
context.getAttribute(AS2ServerConnection.AS2_SIGNING_ALGORITHM);
this.signingCertificateChain = (Certificate[])
context.getAttribute(...AS2_SIGNING_CERTIFICATE_CHAIN);
this.signingPrivateKey = (PrivateKey)
context.getAttribute(...AS2_SIGNING_PRIVATE_KEY);
this.decryptingPrivateKey = (PrivateKey)
context.getAttribute(...AS2_DECRYPTING_PRIVATE_KEY);
this.validateSigningCertificateChain = (Certificate[])
context.getAttribute(...AS2_VALIDATE_SIGNING_CERTIFICATE_CHAIN);
}
{code}
The instance is registered once on the shared HttpProcessor, so it is shared
across requests. The assignment block is not inside the class's lock, and the
values persist after the request that set them. A deployment hosting two
partners on different paths with different keys can therefore have one
request's MDN signed with the other partner's key.
*AS2ServerConnection* creates the HttpContext once outside the request loop:
{code:java}
final HttpContext context = HttpCoreContext.create();
try {
while (!Thread.interrupted()) {
this.httpService.handleRequest(this.serverConnection, context);
...
String recipientAddress =
coreContext.getAttribute(AS2AsynchronousMDNManager.RECIPIENT_ADDRESS,
String.class);
{code}
RECIPIENT_ADDRESS and ASYNCHRONOUS_MDN set while handling one request are still
present on the next iteration, so a later request that does not request an
asynchronous MDN can trigger a resend to the previous request's address.
Proposal: keep the dynamically loaded keys and chains in local variables (or in
the HttpCoreContext) for the duration of process() rather than in instance
fields, and remove RECIPIENT_ADDRESS/ASYNCHRONOUS_MDN from the context after
the send block - or create a fresh context per request. A test that drives two
requests with different key material through one connection would cover both.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)