jetty / jetty/jetty.project

No way to set keystore for JSR 356 websocket clients, needed for SSL client authentication

Open
#155 32 comments 0 reactions 1 assignee Claimed by @joakime View on GitHub
Bug Specification
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.