[ 
https://issues.apache.org/jira/browse/CAMEL-25841?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

shashank updated CAMEL-25841:
-----------------------------
    Description: 
{{XmppComponent.createEndpoint}} (main 20cdb309f7d0) keeps the endpoints it 
creates in a map and returns a cached endpoint for any URI with the same key. 
The key is built from the scheme, host, port and query only:

{code:java}
private String extractCacheKeyFromUri(String uri) throws URISyntaxException {
    URI u = new URI(uri);
    return u.getScheme() + "://" + u.getHost() + u.getPort() + u.getQuery();
}
{code}

The participant (the path) and the user (the user info) are not in the key. So 
{{xmpp://alice@host:5222/bob@host?password=x}} and 
{{xmpp://alice@host:5222/carol@host?password=x}} resolve to the same endpoint, 
the one for bob, and every message sent to the second URI goes to bob. With two 
users on the same server ({{xmpp://alice@host/...}} and 
{{xmpp://dave@host/...}}, same query), the second URI gets the first user's 
endpoint, so messages are sent from alice's account with alice's password. This 
happens with plain {{to}} endpoints in two routes as well as with toD and a 
participant taken from the message, and nothing in the logs shows it (the 
endpoint is only logged at DEBUG as "Using cached endpoint"). The map is also a 
plain HashMap that toD can use from several threads, and it keeps every 
endpoint until the component stops.

*Fix*: remove the component's endpoint cache. The component creates a new 
endpoint for each URI, like other components. The CamelContext already reuses 
the endpoint of the same URI and stops the endpoints it holds, so the cache is 
not needed for clean-up.

The endpoints of one account must still share one connection: with a connection 
per endpoint, {{xmpp://bot@host/alice}} and {{xmpp://bot@host/carol}} log in 
with the same JID and resource ({{Camel}} by default), the server closes the 
older session with a {{conflict}} stream error, and Smack 4.4.8's 
{{ReconnectionManager}} does not reconnect after {{conflict}}, so one endpoint 
would stop working for good. (A distinct resource per endpoint is no fix: a 
message to the bare JID goes to one resource only.) So the component keeps one 
connection per account (host, port, service name, user, password, resource, 
login, connection configuration), used by the consumers and producers of all 
endpoints of that account and closed when the last of them stops; each endpoint 
keeps its own participant, room and other settings. Consumers and producers 
release the connection on stop instead of disconnecting it, and a consumer 
removes its listeners from it.

*Tests*: new {{XmppComponentEndpointPerUriTest}} (3 tests, no XMPP server 
needed). {{endpointPerParticipant}} fails on main: {{expected: 
<carol@localhost> but was: <bob@localhost>}}. {{endpointPerUser}} fails on 
main: {{expected: <dave> but was: <alice>}}. {{sameUriSameEndpoint}} passes on 
main and with the fix. New {{XmppSharedConnectionTest}} (3 tests) with a small 
in-process XMPP server ({{FakeXmppServer}}: plain TCP, SASL PLAIN and 
ANONYMOUS, resource binding, and the {{conflict}} stream error for a second 
session of the same JID and resource); the real Smack client connects to it. 
{{endpointsOfOneAccountShareItsConnection}} (two endpoints of one account send 
to alice and carol over one session) fails on main ({{expected: <[hello alice]> 
but was: <[hello alice, hello carol]>}}) and with a connection per endpoint 
({{expected: <[hello alice]> but was: <[]>}}, the first session was closed with 
{{conflict}}); {{stoppingOneEndpointKeepsTheConnectionOfTheOther}} and 
{{consumerRestartedOnASharedConnectionReceivesEachMessageOnce}} check that a 
stopped endpoint or consumer leaves the shared session to the others and that 
the session is closed with the last route. camel-xmpp unit tests with the fix: 
15 run, 0 failures, 5 skipped (the tests that need an XMPP server container); 
the integration tests were not run.

*How it was found*: a sweep for components that keep endpoints or clients in 
their own maps (state that grows per endpoint and outlives it), then the JUnit 
test above.

*Affected*: main, camel-4.23.x, camel-4.22.x, camel-4.18.x, camel-4.14.x and 
camel-4.10.x (the same cache key; read, not run).

_Filed with Claude Code on behalf of allthingssecurity._


  was:
{{XmppComponent.createEndpoint}} (main 20cdb309f7d0) keeps the endpoints it 
creates in a map and returns a cached endpoint for any URI with the same key. 
The key is built from the scheme, host, port and query only:

{code:java}
private String extractCacheKeyFromUri(String uri) throws URISyntaxException {
    URI u = new URI(uri);
    return u.getScheme() + "://" + u.getHost() + u.getPort() + u.getQuery();
}
{code}

The participant (the path) and the user (the user info) are not in the key. So 
{{xmpp://alice@host:5222/bob@host?password=x}} and 
{{xmpp://alice@host:5222/carol@host?password=x}} resolve to the same endpoint, 
the one for bob, and every message sent to the second URI goes to bob. With two 
users on the same server ({{xmpp://alice@host/...}} and 
{{xmpp://dave@host/...}}, same query), the second URI gets the first user's 
endpoint, so messages are sent from alice's account with alice's password. This 
happens with plain {{to}} endpoints in two routes as well as with toD and a 
participant taken from the message, and nothing in the logs shows it (the 
endpoint is only logged at DEBUG as "Using cached endpoint"). The map is also a 
plain HashMap that toD can use from several threads, and it keeps every 
endpoint until the component stops.

*Fix*: remove the component's endpoint cache. The component creates a new 
endpoint for each URI, like other components. The CamelContext already reuses 
the endpoint of the same URI and stops the endpoints it holds, so the cache is 
not needed for clean-up.

*Tests*: new {{XmppComponentEndpointPerUriTest}} (3 tests, no XMPP server 
needed). {{endpointPerParticipant}} fails on main: {{expected: 
<carol@localhost> but was: <bob@localhost>}}. {{endpointPerUser}} fails on 
main: {{expected: <dave> but was: <alice>}}. {{sameUriSameEndpoint}} passes on 
main and with the fix. camel-xmpp unit tests with the fix: 12 run, 0 failures, 
5 skipped (the tests that need an XMPP server container); the integration tests 
were not run.

*How it was found*: a sweep for components that keep endpoints or clients in 
their own maps (state that grows per endpoint and outlives it), then the JUnit 
test above.

*Affected*: main, camel-4.23.x, camel-4.22.x, camel-4.18.x, camel-4.14.x and 
camel-4.10.x (the same cache key; read, not run).

_Filed with Claude Code on behalf of allthingssecurity._



> camel-xmpp - two endpoints that differ only in the participant or the user 
> are the same endpoint, so messages go to the wrong participant or from the 
> wrong account
> -------------------------------------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: CAMEL-25841
>                 URL: https://issues.apache.org/jira/browse/CAMEL-25841
>             Project: Camel
>          Issue Type: Bug
>          Components: camel-xmpp
>            Reporter: shashank
>            Assignee: shashank
>            Priority: Major
>
> {{XmppComponent.createEndpoint}} (main 20cdb309f7d0) keeps the endpoints it 
> creates in a map and returns a cached endpoint for any URI with the same key. 
> The key is built from the scheme, host, port and query only:
> {code:java}
> private String extractCacheKeyFromUri(String uri) throws URISyntaxException {
>     URI u = new URI(uri);
>     return u.getScheme() + "://" + u.getHost() + u.getPort() + u.getQuery();
> }
> {code}
> The participant (the path) and the user (the user info) are not in the key. 
> So {{xmpp://alice@host:5222/bob@host?password=x}} and 
> {{xmpp://alice@host:5222/carol@host?password=x}} resolve to the same 
> endpoint, the one for bob, and every message sent to the second URI goes to 
> bob. With two users on the same server ({{xmpp://alice@host/...}} and 
> {{xmpp://dave@host/...}}, same query), the second URI gets the first user's 
> endpoint, so messages are sent from alice's account with alice's password. 
> This happens with plain {{to}} endpoints in two routes as well as with toD 
> and a participant taken from the message, and nothing in the logs shows it 
> (the endpoint is only logged at DEBUG as "Using cached endpoint"). The map is 
> also a plain HashMap that toD can use from several threads, and it keeps 
> every endpoint until the component stops.
> *Fix*: remove the component's endpoint cache. The component creates a new 
> endpoint for each URI, like other components. The CamelContext already reuses 
> the endpoint of the same URI and stops the endpoints it holds, so the cache 
> is not needed for clean-up.
> The endpoints of one account must still share one connection: with a 
> connection per endpoint, {{xmpp://bot@host/alice}} and 
> {{xmpp://bot@host/carol}} log in with the same JID and resource ({{Camel}} by 
> default), the server closes the older session with a {{conflict}} stream 
> error, and Smack 4.4.8's {{ReconnectionManager}} does not reconnect after 
> {{conflict}}, so one endpoint would stop working for good. (A distinct 
> resource per endpoint is no fix: a message to the bare JID goes to one 
> resource only.) So the component keeps one connection per account (host, 
> port, service name, user, password, resource, login, connection 
> configuration), used by the consumers and producers of all endpoints of that 
> account and closed when the last of them stops; each endpoint keeps its own 
> participant, room and other settings. Consumers and producers release the 
> connection on stop instead of disconnecting it, and a consumer removes its 
> listeners from it.
> *Tests*: new {{XmppComponentEndpointPerUriTest}} (3 tests, no XMPP server 
> needed). {{endpointPerParticipant}} fails on main: {{expected: 
> <carol@localhost> but was: <bob@localhost>}}. {{endpointPerUser}} fails on 
> main: {{expected: <dave> but was: <alice>}}. {{sameUriSameEndpoint}} passes 
> on main and with the fix. New {{XmppSharedConnectionTest}} (3 tests) with a 
> small in-process XMPP server ({{FakeXmppServer}}: plain TCP, SASL PLAIN and 
> ANONYMOUS, resource binding, and the {{conflict}} stream error for a second 
> session of the same JID and resource); the real Smack client connects to it. 
> {{endpointsOfOneAccountShareItsConnection}} (two endpoints of one account 
> send to alice and carol over one session) fails on main ({{expected: <[hello 
> alice]> but was: <[hello alice, hello carol]>}}) and with a connection per 
> endpoint ({{expected: <[hello alice]> but was: <[]>}}, the first session was 
> closed with {{conflict}}); 
> {{stoppingOneEndpointKeepsTheConnectionOfTheOther}} and 
> {{consumerRestartedOnASharedConnectionReceivesEachMessageOnce}} check that a 
> stopped endpoint or consumer leaves the shared session to the others and that 
> the session is closed with the last route. camel-xmpp unit tests with the 
> fix: 15 run, 0 failures, 5 skipped (the tests that need an XMPP server 
> container); the integration tests were not run.
> *How it was found*: a sweep for components that keep endpoints or clients in 
> their own maps (state that grows per endpoint and outlives it), then the 
> JUnit test above.
> *Affected*: main, camel-4.23.x, camel-4.22.x, camel-4.18.x, camel-4.14.x and 
> camel-4.10.x (the same cache key; read, not run).
> _Filed with Claude Code on behalf of allthingssecurity._



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to