Greetings all, Pretty sure I found a bug in the way org.apache.openejb.client.MulticastConnectionFactory decodes URL parameters. The final result of the issue is that if you use HTTP basic authentication when calling ServerServlet and openejb.ejbd.authenticate-with-request=true, you can't login with a password that contains an ampersand character.
The flow looks something like: 1) Create a new IntitialContext with PROVIDER_URL set to failover:sticky+random:https://myserver/ejb/invoke?basic.username=xyz&basic.password=pass%26word a) /ejb/invoke is where I have org.apache.openejb.server.httpd.ServerServlet mapped b) web.xml on that mapping requires BASIC auth. c) key part of URL is the literal password "pass&word" URL encoded with ampersand -> %26 2) TomEE internals eventually end up at HttpConnectionFactory$HttpConnection's constructor where line 76 calls: params = MulticastConnectionFactory.URIs.parseParamters(uri); By this time, various unwrapping has paired the URL down to: https://myserver/ejb/invoke?basic.username=xyz&basic.password=pass%26word 3) MulticastConnectionFactory...parseParameters, IE line 136: return uri.getQuery() == null ? new HashMap<String, String>(0) : parseQuery(stripPrefix(uri.getQuery(), "?")); That calls URI.getQuery() which decodes the URI's query string, then passes that into parseQuery() which splits up the query parameters delimited by ampersands. The call to URI.getQuery() is the problem. For the above URI, the result is: basic.username=xyz&basic.password=pass&word The ampersand in the query parameter basic.password is decoded and then indistinguishable from a query parameter separator. When passed into parseQuery, the resulting value for basic.password is just "pass". Since MulticastConnectionFactory$URIs::parseQuery already calls URLDecoder.decode() on both name and value pairs, the call in parseParameters should be to URI::getRawQuery() instead of getQuery(). I think there's also a possible double decoding issue here which could corrupt certain values by decoding the value a second time. For the time being, I think I can work around this by passing the authorization query parameter with the user:pass already base64 encoded. Pretty sure this should be a complete & safe fix: diff --git a/server/openejb-client/src/main/java/org/apache/openejb/client/MulticastConnectionFactory.java b/server/openejb-client/src/main/java/org/apache/openejb/client/MulticastConnectionFactory.java index 22f2f86a6a..eedb54840e 100644 --- a/server/openejb-client/src/main/java/org/apache/openejb/client/MulticastConnectionFactory.java +++ b/server/openejb-client/src/main/java/org/apache/openejb/client/MulticastConnectionFactory.java @@ -133,7 +133,7 @@ public class MulticastConnectionFactory implements ConnectionFactory { } public static Map<String, String> parseParamters(final URI uri) throws URISyntaxException { - return uri.getQuery() == null ? new HashMap<String, String>(0) : parseQuery(stripPrefix(uri.getQuery(), "?")); + return uri.getQuery() == null ? new HashMap<String, String>(0) : parseQuery(stripPrefix(uri.getRawQuery(), "?")); } public static String stripPrefix(final String value, final String prefix) { Best regards, Zac Bedell
signature.asc
Description: Message signed with OpenPGP