Open jmcc0nn3ll opened 8 years ago
Hopefully, the next version of JSR356 (javax.websocket) will address this flaw in the API.
I agree with @jmcc0nn3ll to provide at least a fix the overloaded constructor in the next version
Since the only sanctioned way to create a JSR356 WebSocket client is to call the javax.websocket.ContainerProvider.getWebSocketContainer()
...
example:
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
EchoEndpoint echoer = new EchoEndpoint();
Session session = container.connectToServer(echoer,URI.create("ws://remote/echo");
session.getBasicRemote().sendText("Echo");
... there's no opportunity to use a new constructor version, even if it existed.
The functionality you are looking for simply does not exist for the JSR356 API.
It does, however, exist for the Jetty Native Websocket API (which is the original, non-JSR356, more capable, WebSocket API Jetty provides)
I can explain the use case where I ran into this.
I need ajavax.websocket.WebSocketContainer
to pass into org.springframework.web.socket.client.standard.StandardWebSocketClient
and I can build up a simple org.eclipse.jetty.websocket.jsr356.ClientContainer
with a WebSocketContainerScope
(SimpleContainerScope
) that specifies the SslContextFactory
, BUT the constructor does not use the SslContextFactory
from the WebSocketContainer
scope and instead creates a new one on the third line of the contructor in order to consume the org.eclipse.jetty.websocket.jsr356.ssl-trust-all
system property.
public ClientContainer(WebSocketContainerScope scope)
{
boolean trustAll = Boolean.getBoolean("org.eclipse.jetty.websocket.jsr356.ssl-trust-all");
this.scopeDelegate = scope;
client = new WebSocketClient(scope, new SslContextFactory(trustAll));
client.setEventDriverFactory(new JsrEventDriverFactory(client.getPolicy()));
SessionFactory sessionFactory = new JsrSessionFactory(this,this,client);
client.setSessionFactory(sessionFactory);
addBean(client);
this.endpointClientMetadataCache = new ConcurrentHashMap<>();
this.decoderFactory = new DecoderFactory(this,PrimitiveDecoderMetadataSet.INSTANCE);
this.encoderFactory = new EncoderFactory(this,PrimitiveEncoderMetadataSet.INSTANCE);
ShutdownThread.register(this);
}
It's more an issue when plugging into other libraries that use JSR356 API than using pure JSR356 API websockets.
Since JSR356 Client uses WebSocketClient, and WebSocketClient uses the internal HttpClient, the decisions being made in Issue #1528 should provide a technique to configure any HttpClient specific features, even on JSR356.
jetty-9.4.x (jetty-9.4.7-SNAPSHOT) and master (jetty-10.x) branches have support for this via configuration of the internal HttpClient now.
jetty-9.4.x (jetty-9.4.7-SNAPSHOT) and master (jetty-10.x) branches have support for this via configuration of the internal HttpClient now.
Do you have any examples how to configure client authentication in http client? (For websockets).
The AuthenticationStore is probably were you want to look. https://www.eclipse.org/jetty/documentation/current/http-client-authentication.html
Feel free to open a new issue, show some sample code and what you are attempting to do.
Sorry I was not clear. I am looking an example for SSL client authentication. When you set the "needClientAuth" to true on SslContextFactory, client is expected to send its certificate, but as mentioned in this ticket, it is not. As this ticket is already closed, I am looking at how to configure jetty http client to provide a custom ssl context factory or any other way to take the key store into account and send the certificate.
Thanks.
Can you please also show me an example, how to configure the jetty http client programatically which is used to make websocket calls?
That is unrelated to this closed issue. Please open a new issue.
Thank you joakime, but I will probably create the same ticket as this one. "No way to set keystore for JSR 356 websocket clients, needed for SSL client authentication #155". So, wondering how is this ticket closed? I am looking the solution for this ticket. How do I set the keystore here?
you are asking about behaviors before even the HTTP level. client certificate auth has nothing to do with websocket. once the client certificate auth is valid/verified on the server, then the HTTP protocol begins, which asks to upgrade, then the websocket upgrade can proceed.
I don't think you are getting my questions. What I am asking is how to force the http client used internally to send certificate during tls handshake. This was the original issue also reported in this ticket. ("No way to set keystore"). The client is not sending its certificate to the server.
@bahadirdanisik to force HttpClient
to send the certificate you need to set SslContextFactory.needClientAuth=true
on the server.
It's the server that asks the client to send the certificate.
Yes, I know and already set the needClientAuth=true. This is asking client to send the cert, but the client does not send anything as indicated in this ticket. The httpClient used by Jetty does not honor the keystore settings. It does not send the certificate to the server.
Please pack a reproducible test case and attach it to this issue.
Any update for this ticket? Thanks.
@bahadirdanisik no updates because there is nothing to do.
It is already possible to configure the client and the server so that the client sends to the server a certificate to authenticate itself, and we know that that works: we have tests and other people using this setup.
You have been asked a reproducible case for your issue, but you did not.
I did not find a way to make a jetty websocket client send a ssl client certificate for auth over websocket to the server (as opposed to a websocket client from the browser that does it to the same server - so the server is configured to ask for client certs)
Please @sbordet can you give any references/examples (you said - we have tests) with a jetty websocket client being able to send a ssl client certificate for auth to a server (any server) ?
Thanks
@horiavmuntean this issue is for the JSR356 WebSocket Client in Jetty (using the javax.websocket.WebSocketContainer
API).
What you are asking about ("jetty websocket client") is a different client (org.eclipse.jetty.websocket.client.WebSocketClient
API).
Can you open a new issue with what you have attempted so far, some example code on how you setup the WebSocketClient
, what results you have (logs are great here), and what you expect.
Hi @joakime , thanks for clarifications. In the meantime I "solved" the problem by upgrading from 9.2.2 to 9.4.17.
Hi. I've been having the same issue (or at least it looks that way) trying to get SSL working with the jsr356 websockets jetty support. As I've seen in various comments on the many threads on this issue I configure a HttpClient pass in the same SSLContext, SslContextFactory.setSslContext(sslContext) and then new HttpClient(SslContextFactory).
Finding the exact means of addressing this is proving quite laborious. The error I get is
sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXV
Nothing I try seems to deal with this.
The SSLContext we build we use to create jaxrs client so that (at least for rest) works.
The jetty version I"m using is 9.4.20.v20190813 which I thought (from on of the threads) these problems had been fixed.
In case it helps the code looks like this.
final ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
final SslContextFactory ssl = new SslContextFactory.Client();
final SSLContext sslContext = //our factory creates the sslcontext;
ssl.setSslContext(sslContext);
HttpClient httpClient = new HttpClient(ssl);
context.setAttribute(HTTPCLIENT_ATTRIBUTE, httpClient);
ServerContainer websocketsContainer = WebSocketServerContainerInitializer.initialize(context);
I see in initialise(context) that the http client is read from the context and then used to eventually create the WebSocketClient. Providing the HttpClient that this doesn't seem to work at all, am I missing something?
Thanks
Mark
unable to find valid certification path to requested target
@melowe this says that the server sent down to the client a certificate that is either self-signed or the client does not know how to trust - it's a normal TLS failure due to the client TLS configuration being misconfigured.
sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.validator.PKIXV
If you are getting the above you are definitely using SSL/TLS for your connection. (it's trying to handshake) You just have a SSL/TLS configuration issue to work out.
@melowe I went ahead and added an example of configuring javax.websocket client for SSL on Jetty (in commit 5bcbe0f9d9ab83c14584b63ef2ffe18579f89f9e)
See directory: javax-websocket-client-impl - /examples/
And the main entry point : SecureWebSocketContainerExample.java
This is just the javax.websocket equivalent of the same code at jetty-client - /examples/SimpleSecureEchoClient.java
thanks joakime.
so I found the issue(s). when the dust settles I see if i can send some patches.
JettyClientContainerProvider doesn't have any direct means of injecting the sslContext. Adding a static reference to the JettyClientContainerProvider and some like
SimpleContainerScope containerScope = new SimpleContainerScope(WebSocketPolicy.newClientPolicy());
if (sslContext != null) {
final SslContextFactory ssl = new SslContextFactory.Client();
ssl.setSslContext(sslContext);
containerScope.setSslContextFactory(ssl);
}
ClientContainer clientContainer = new ClientContainer(containerScope);
This makes ContainerProvider.getContainer() work. This does create a different issue where the injection via a static function of the sslContext means these cannot be created in start up, but need to be created as there's no way of knowing whether the context has been provided or not.
The previous way of providing the http client as a server attribute to the WebSocketServerContainerInitializer works fine.
The provision of the objects provided in the xml is the part of your example that would make the difference but we're not using xml config so we had to find an alternative. The configurator and the non annotated endpoint seem to make no difference.
Hmm ... SimpleContainerScope
is an internal class, and its been removed in Jetty 10 already.
Let me make a new ClientContainer(HttpClient)
constructor that can be used to configure the HttpClient side (for ssl, and proxies).
But that means you cannot use javax.websocket.ContainerProvider.getWebSocketContainer()
.
Would this be acceptable?
Opened PR #4019 for new ClientContainer(HttpClient)
optional constructor.
It would be used like this ...
So injecting the http client rather than the scope seems fine. But I'm not sure how to deal with the javax.websocket.ContainerProvider you end up with a race condition between when the clients are created and when the addition of the SSLContext is added. I guess some block until initialised, initialisation being JettyClientContainerProvider.configured() or something.. and getContainer() can block with a timeout or something..
See previous https://github.com/eclipse/jetty.project/issues/155#issuecomment-524387906 for example on how PR #4019 would work.
But I'm not sure how to deal with the javax.websocket.ContainerProvider you end up with a race condition between when the clients are created and when the addition of the SSLContext is added.
This is why the XML configuration was provided as an option.
Your XML can choose do anything it wants, just as long as it <Configure class="org.eclipse.jetty.client.HttpClient">
, go load a ssl configuration from a DB, access a singleton to get your tls configuration, have it use a shared thread pool, etc...
You are correct, you cannot modify the SSL configuration (even the SSLContext) once the javax.websocket.WebSocketContainer
is created.
The javax.websocket.ContainerProvider.getWebSocketContainer()
is a java.util.ServiceLoader
that calls JettyClientContainerProvider
and should not block or timeout.
You could even have that XML delegate to your own class, block in there if you want to.
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure id="myHttpClient" class="org.eclipse.jetty.client.HttpClient">
<Arg>
<New class="org.eclipse.jetty.util.ssl.SslContextFactory$Client" />
</Arg>
<Call class="examples.CustomHttpClientConfig" name="configure">
<Arg><Ref refid="myHttpClient"/></Arg>
</Call>
</Configure>
Where the class looks like ...
package examples;
import org.eclipse.jetty.client.HttpClient;
public class CustomHttpClientConfig
{
public static void configure(HttpClient httpClient)
{
httpClient.getSslContextFactory().setExcludeCipherSuites(); // echo.websocket.org uses WEAK cipher suites
httpClient.setIdleTimeout(5000);
}
}
... a race condition between when the clients are created ...
This is a red flag!
You should only use that call once; either once for your JVM, or once per deployed WebApp, as its a heavyweight component.
There should never be multiple accesses to javax.websocket.ContainerProvider.getWebSocketContainer()
.
It will return a new Client container on every call. (This is important to recognize)
So the only means of injecting the sslcontext into the HttpClient (via scope or otherwise) is by using the xml config. The point that the Container should be present and correct when getContainer is called is fair enough. I didn't find anything in the spec regarding how implementations should not block etc, but blocking is less than ideal.
I think we'll need to resolve this but providing our own JettyClientContainerProvider that can load the SSLContext config internally or even a HttpClientFactory that can read the SSLContext.
I've been looking in the jetty code, is there no equivalent of the xml http client config that can be done programmatically?
migrated from Bugzilla #442926 status ASSIGNED severity normal in component websocket for 9.3.x Reported in version 9.2.2 on platform All Assigned to: Joakim Erdfelt
On 2014-08-29 17:11:16 -0400, Stephen McCracken wrote:
On 2014-08-29 18:16:51 -0400, Stephen McCracken wrote:
On 2014-09-22 15:52:15 -0400, Joakim Erdfelt wrote:
On 2015-12-28 17:06:36 -0500, Peter Robbins wrote: