No way to set keystore for JSR 356 websocket clients, needed for SSL client authentication
- Dominant language
- Java
- Stars
- 4.1k
- Forks
- 2k
- Avg merge
- 3d 56m
- Merged PRs (30d)
- 48
Description
migrated from Bugzilla [#442926](https://bugs.eclipse.org/bugs/show_bug.cgi?id=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:
> I'm trying to write a websocket client that uses the standard JSR 356 APIs and the corresponding jetty implementation in javax-websocket-client-impl (9.2.2.v20140723). Without SSL client authentication, everything works. However, when I set up the jetty server to require client authentication (jetty.ssl.needClientAuth=true and jetty.ssl.wantClientAuth=true in start.d/ssl.ini), the client cannot connect.
>
> If I run the jetty server with -Djavax.net.debug=SSL, the source of the problem seems to be that the client is not providing a certificate chain.
>
> **\* Certificate chain
> ---
>
> qtp939427899-19, fatal error: 42: null cert chain
> javax.net.ssl.SSLHandshakeException: null cert chain
>
> Based on internet searching, this probably means that the client keystore is missing or has the wrong content.
>
> Based on an inspection of the code for the following classes:
> - org.eclipse.jetty.util.ssl.SslContextFactory and
> - org.eclipse.jetty.websocket.jsr356.ClientContainer
> - org.eclipse.jetty.websocket.client.WebSocketClient
> I do not see a way to configure the client keystore.
>
> I have tried several ways that did not work. Defining the following properties on the client command line did not help:
> -Djavax.net.ssl.keyStore
> -Djavax.net.ssl.keyStorePassword
> -Djetty.keystore
> -Djetty.keystore.password
>
> I also tried manually configuring the SslContextFactory, but it seems that I can't get access to it until "too late". The following code produces the exception below it.
>
> WebSocketContainer container = ContainerProvider.getWebSocketContainer();
> if (container instanceof ClientContainer) {
> ClientContainer jettyClientContainer = (ClientContainer) container;
> jettyClientContainer.getClient().getSslContextFactory().setKeyStorePath(keystorePath);
> jettyClientContainer.getClient().getSslContextFactory().setKeyStorePassword(keystorePassword);
> }
>
> java.lang.IllegalStateException: Cannot modify configuration when STARTED
> at org.eclipse.jetty.util.ssl.SslContextFactory.checkNotStarted(SslContextFactory.java:1114)
> at org.eclipse.jetty.util.ssl.SslContextFactory.setKeyStorePath(SslContextFactory.java:439)
> at org.example.WsTestClient.main(WsTestClient.java:49)
On 2014-08-29 18:16:51 -0400, Stephen McCracken wrote:
> Tyrus claims to pick up a default keystore, but requires non-JSR classes to configure it in code.
> https://tyrus.java.net/documentation/1.8.2/user-guide.html#d0e1128
On 2014-09-22 15:52:15 -0400, Joakim Erdfelt wrote:
> That is absolutely 100% correct.
> There is no way.
>
> There is an open / unresolved spec bug for this at https://java.net/jira/browse/WEBSOCKET_SPEC-210
On 2015-12-28 17:06:36 -0500, Peter Robbins wrote:
> This also impacts when you need to programmatically provide truststore to ClientContainer.
>
> ```
> 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);
> }
> ```
>
> WebSocketContainerScope has the getSslContextFactory() method that would allow to inject an SslContextFactory using a the proper truststore.
>
> This line overrides that:
> client = new WebSocketClient(scope, new SslContextFactory(trustAll));
>
> This is seemingly done to consume the org.eclipse.jetty.websocket.jsr356.ssl-trust-all system property. I think that should be consumed somewhere other than the ClientContainer constructor. Perhaps somewhere in SimpleContainerScope?
Contributor guide
Assessment
This issue has not been assessed yet.