How to configure Play! 2.4.2 HTTPS keystore?
Asked Answered
S

1

9

I'm new to the Play Framework and just trying to get HTTPS going for the first time with 2.4.2 on Java 8. I can get it working with the default keystore but not with my own keystore. I configured the working default keystore in build.sbt:

javaOptions ++= Seq(
    "-Dhttps.port=9443"
)

Then the official documentation for configuring your own keystore gets a bit too abstract for me. It mentions configuring it in application.conf but doesn't say how, or on the command line but not with a Java example. Googling reveals some Scala examples but I cannot cajole them as they use things like devSettings that don't seem to come across to the Java world, or at least I do not understand Play and Scala enough to get a grip on them.

So as far as I know I seem to be using my own unique configuration in build.sbt:

javaOptions ++= Seq(
    "-Dhttps.port=9443",
    "-Dhttps.keyStore.path=keystore.jks",
    "-Dhttps.keyStore.password=password")

It builds and runs ok:

p.c.s.NettyServer - Listening for HTTPS on port /0:0:0:0:0:0:0:0:9443
play.api.Play - Application started (Dev)

But on the first https:// access I get an endless stack trace in the Actuator UI:

play.core.server.NettyServer$PlayPipelineFactory - cannot load SSL context
java.lang.reflect.InvocationTargetException: null
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_45]
    ...
play.core.server.netty.PlayDefaultUpstreamHandler - Exception caught in Netty
java.lang.IllegalArgumentException: empty text
    at org.jboss.netty.handler.codec.http.HttpVersion.<init>(HttpVersion.java:89) ~[netty-3.10.3.Final.jar:na]
    ...

My first thought is that I'm not configuring it correctly but I haven't managed to find a definitive guide for Play 2.4. I'm seriously starting to question my Googling powers. I find lots of references to front-end proxies and avoiding SSL termination in Play but I'm not developing a public website and find this approach overkill.

I don't know if it's a red herring but the Netty project dropped the org.jboss.netty a long time ago and now uses io.netty. I see org.jboss.netty all over the stack trace and Play 2.4.2 seems to be using Netty 3.10.3.Final which is very old. I happen to be familiar with Netty and have used 4.x in production while 5.x is currently in Alpha. Why is Play stuck in the past here? Should I be worried?

I found several issues which seem closely related such as a bug in Play 2.2.x and a bug in AHC (which Play uses), but both appear to have been fixed well before Play 2.4.2 that I'm using. Nevertheless I tried fixes such as upgrading the async-http-client dependency, excluding the org.jboss.netty transitive dependency from async-http-client and upgrading to Netty 3.10.4.Final.

So now I'm stuck but I feel like I'm just missing a getting started guide. Maybe all these dependency issues and related bugs are just a waste of time?

Stalinist answered 31/7, 2015 at 10:39 Comment(2)
docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/…Neese
@WillSargent Are you saying that I am directly setting JVM parameters here with javaOptions? Should that be my aim? I.e. isn't there another way to apply these settings with something like devSettings? I'm not sure what I'd gain here but maybe more control over different development and production deployments? It also seems these javaOptions do not apply to my tests (can't test ssl enforcement). This is likely due to my lack of understanding with the testing framework as much as anything but as I said I feel like I've configured the ssl at the wrong level.Stalinist
S
7

So 5 minutes after posting the question I figured it out... My configuration keys were wrong and the keystore path needed to be either absolute or relative to the project root (i.e. add conf/ if it's in your conf folder):

javaOptions ++= Seq(
    "-Dhttps.port=9443",
    "-Dhttps.keyStore=conf/keystore.jks",
    "-Dhttps.keyStorePassword=password")

My mistake with the keys was to use dots per the documentation:

https.keyStore.path
https.keyStore.password

Instead of:

https.keyStore
https.keyStorePassword

I'm not sure how one gets from dot.notation to camelCase or even what exactly I'm configuring here. These parameters are more like the standard JVM arguments javax.net.ssl.keyStore and javax.net.ssl.keyStorePassword, yet not quite. I feel like I'm missing a trick here. It would also be nice if Play would report that it couldn't find the keystore rather than an NPE, but since I seem to be configuring the JVM maybe there's nothing Play can do about it unless there is another way to configure this stuff... with decent documentation!

Stalinist answered 31/7, 2015 at 11:14 Comment(6)
The settings in the HTTPS documentation should appear in application.conf, but they should work from system properties as well. Can you file an issue at github.com/playframework/playframework/issues and I'll take a look?Neese
Also, the source code for the SSL Engine provider (which configures HTTPS for Play) is here: github.com/playframework/playframework/blob/master/framework/…Neese
How were you running your application when you were finding that configuration via application.conf didn't work?Galbraith
(first time commenting, didn't realise enter would submit rather than add a newline!) What I mean is were you using the activator/sbt run task, or had you staged your application and ran the generated script? I ask because in figuring out some things for myself I noticed playframework.com/documentation/2.4.x/…, which states: "This means that the HTTP server cannot access the application.conf file when it starts.... Instead, you need to either use system properties or the devSettings setting shown above...."Galbraith
I was running locally under activator/sbt and that "cannot access" comment led me to try the devSettings in build.sbt, but it then complained that devSettings was undefined and anyway I couldn't work out what the keys should be. That's when I stumbled on javaOptions but, as I said, this feels wrong and I would like to find out how to apply these settings with devSettings in Play+Java.Stalinist
So at least we understand why values in application.conf don't apply when using the run task. As for devSettings, I've just tried using it myself and also had problems. I defined it as: ``` PlayKeys.devSettings := Seq( "play.server.http.port" -> "disabled", "play.server.https.port" -> "9443" ) ``` It was parsed etc. fine, and the run task runs, but without any regard for the port override - it just listened on 9000. So I'm afraid I can't help, I can only confirm I had a similar problem. I'm now just using javaOptions.Galbraith

© 2022 - 2024 — McMap. All rights reserved.