Permalink
Browse files

Updated the way Play uses application.secret

Fixes #1775.

* Play now generates an application secret that is stable to the place
  where the application is running from in dev and test mode.
* Play will fail to load if application secret is not set or changeme in
  production.
* Created new SBT tasks for generating and updating the application
  secret.
* Wrote new docs on the application secret, how configure it, and best
  practices.
* Updated production documentation to refer to activator.
  • Loading branch information...
1 parent 2aa41b8 commit 4daa9193a80c1ea2fb364ec3ccf4b48f3d40cd37 @jroper jroper committed Mar 28, 2014
Showing with 360 additions and 37 deletions.
  1. +1 −0 documentation/manual/Home.md
  2. +75 −0 documentation/manual/detailedTopics/configuration/ApplicationSecret.md
  3. +2 −0 documentation/manual/detailedTopics/configuration/Configuration.md
  4. +2 −0 documentation/manual/detailedTopics/configuration/SettingsJDBC.md
  5. +2 −0 documentation/manual/detailedTopics/configuration/SettingsLogger.md
  6. +2 −0 documentation/manual/detailedTopics/configuration/ThreadPools.md
  7. +1 −0 documentation/manual/detailedTopics/configuration/_Sidebar.md
  8. +15 −14 documentation/manual/detailedTopics/production/Production.md
  9. +2 −2 documentation/manual/detailedTopics/production/ProductionConfiguration.md
  10. +7 −7 documentation/manual/detailedTopics/production/ProductionDist.md
  11. BIN documentation/manual/detailedTopics/production/images/dist.png
  12. BIN documentation/manual/detailedTopics/production/images/stage.png
  13. BIN documentation/manual/detailedTopics/production/images/start.png
  14. +1 −0 framework/src/play-integration-test/src/test/resources/application.conf
  15. +57 −0 framework/src/play-integration-test/src/test/scala/play/it/libs/CryptoSpec.scala
  16. +56 −12 framework/src/play/src/main/scala/play/api/libs/Crypto.scala
  17. +3 −0 framework/src/sbt-plugin/src/main/scala/PlayKeys.scala
  18. +5 −2 framework/src/sbt-plugin/src/main/scala/PlaySettings.scala
  19. +68 −0 framework/src/sbt-plugin/src/main/scala/play/sbtplugin/ApplicationSecretGenerator.scala
  20. +4 −0 framework/src/sbt-plugin/src/sbt-test/play-sbt-plugin/secret/README
  21. +10 −0 framework/src/sbt-plugin/src/sbt-test/play-sbt-plugin/secret/conf/application.conf
  22. +30 −0 framework/src/sbt-plugin/src/sbt-test/play-sbt-plugin/secret/project/Build.scala
  23. +4 −0 framework/src/sbt-plugin/src/sbt-test/play-sbt-plugin/secret/project/build.properties
  24. +11 −0 framework/src/sbt-plugin/src/sbt-test/play-sbt-plugin/secret/project/plugins.sbt
  25. +2 −0 framework/src/sbt-plugin/src/sbt-test/play-sbt-plugin/secret/test
@@ -38,6 +38,7 @@
1. [[Working with the in-memory H2 database|Developing-with-the-H2-Database]]
1. [[Managing database evolutions|Evolutions]]
1. [[Configuration file syntax and features|Configuration]]
+ 1. [[Configuring the application secret|ApplicationSecret]]
1. [[Configuring the JDBC connection pool|SettingsJDBC]]
1. [[Configuring Play's thread pools|ThreadPools]]
1. [[Configuring logging|SettingsLogger]]
@@ -0,0 +1,75 @@
+# The Application Secret
+
+Play uses a secret key for a number of things, including:
+
+* Signing session cookies and CSRF tokens
+* Built in encryption utilities
+
+It is configured in `application.conf`, with the property name `application.secret`, and defaults to `changeme`. As the default suggests, it should be changed for production.
+
+> When started in prod mode, if Play finds that the secret is not set, or if it is set to `changeme`, Play will throw an error.
+
+## Best practices
+
+Anyone that can get access to the secret will be able to generate any session they please, effectively allowing them to log in to your system as any user they please. Hence it is strongly recommended that you do not check your application secret into source control. Rather, it should be configured on your production server. This means that it is considered bad practice to put the production application secret in `application.conf`.
+
+One way of configuring the application secret on a production server is to pass it as a system property to your start script. For example:
+
+```bash
+/path/to/yourapp/bin/yourapp -Dapplication.secret="QCY?tAnfk?aZ?iwrNwnxIlR6CTf:G3gf:90Latabg@5241AB`R5W:1uDFN];Ik@n"
+```
+
+This approach is very simple, and we will use this approach in the Play documentation on running your app in production mode as a reminder that the application secret needs to be set. In some environments however, placing secrets in command line arguments is not considered good practice. There are two ways to address this.
+
+### Environment variables
+
+The first is to place the application secret in an environment variable. In this case, we recommend you place the following configuration in your `application.conf` file:
+
+ application.secret="changeme"
+ application.secret=${?APPLICATION_SECRET}
+
+The second line in that configuration sets the secret to come from an environment variable called `APPLICATION_SECRET` if such an environment variable is set, otherwise, it leaves the secret unchanged from the previous line.
+
+This approach works particularly well for cloud based deployment scenarios, where the normal practice is to set passwords and other secrets via environment variables that can be configured through the API for that cloud provider.
+
+### Production configuration file
+
+Another approach is to create a `production.conf` file that lives on the server, and includes `application.conf`, but also overrides any sensitive configuration, such as the application secret and passwords.
+
+For example:
+
+ include "application"
+
+ application.secret="QCY?tAnfk?aZ?iwrNwnxIlR6CTf:G3gf:90Latabg@5241AB`R5W:1uDFN];Ik@n"
+
+Then you can start Play with:
+
+```bash
+/path/to/yourapp/bin/yourapp -Dconfig.file=/path/to/production.conf
+```
+
+## Generating an application secret
+
+Play provides a utility that you can use to generate a new secret. Run `play-generate-secret` in the Play console. This will generate a new secret that you can use in your application. For example:
+
+```
+[my-first-app] $ play-generate-secret
+[info] Generated new secret: QCYtAnfkaZiwrNwnxIlR6CTfG3gf90Latabg5241ABR5W1uDFNIkn
+[success] Total time: 0 s, completed 28/03/2014 2:26:09 PM
+```
+
+## Updating the application secret in application.conf
+
+Play also provides a convenient utility for updating the secret in `application.conf`, should you want to have a particular secret configured for development or test servers. This is often useful when you have encrypted data using the application secret, and you want to ensure that the same secret is used every time the application is run in dev mode.
+
+To update the secret in `application.conf`, run `play-update-secret` in the Play console:
+
+```
+[my-first-app] $ play-update-secret
+[info] Generated new secret: B4FvQWnTp718vr6AHyvdGlrHBGNcvuM4y3jUeRCgXxIwBZIbt
+[info] Updating application secret in /Users/jroper/tmp/my-first-app/conf/application.conf
+[info] Replacing old application secret: application.secret="changeme"
+[success] Total time: 0 s, completed 28/03/2014 2:36:54 PM
+```
+
+> **Next:** [[Configuring the JDBC connection pool|SettingsJDBC]]
@@ -386,3 +386,5 @@ For powers of two, exactly these strings are supported:
For an application's config, Java system properties _override_ settings found in the configuration file. This supports specifying config options on the command line. ie. `play -Dkey=value run`
Note : Play forks the JVM for tests - and so to use command line overrides in tests you must add `Keys.fork in Test := false` in `build.sbt` before you can use them for a test.
+
+> **Next:** [[Configuring the application secret|ApplicationSecret]]
@@ -96,3 +96,5 @@ db.default.maxConnectionAge=1 hour
# The maximum query execution time. Queries slower than this will be logged as a warning.
db.queryExecuteTimeLimit=1 second
```
+
+> **Next:** [[Configuring Play's thread pools|ThreadPools]]
@@ -88,3 +88,5 @@ Specify another logback configuration file to be loaded from an URL:
```
$ start -Dlogger.url=http://conf.mycompany.com/logger.xml
```
+
+> **Next:** [[Configuring gzip encoding|GzipEncoding]]
@@ -111,3 +111,5 @@ Then in your code, you would create futures and pass the relevant execution cont
### Few specific thread pools
This is a combination between the many specific thread pools and the highly synchronized profile. You would do most simple IO in the default execution context and set the number of threads there to be reasonably high (say 100), but then dispatch certain expensive operations to specific contexts, where you can limit the number of them that are done at one time.
+
+> **Next:** [[Configuring logging|SettingsLogger]]
@@ -2,6 +2,7 @@
### Configuration
- [[Configuration file syntax and features | Configuration]]
+- [[Configuring the application secret|ApplicationSecret]]
- [[Configuring the JDBC connection pool | SettingsJDBC]]
- [[Configuring Play's thread pools | ThreadPools]]
- [[Configuring logging | SettingsLogger]]
@@ -1,63 +1,64 @@
<!--- Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com> -->
# Starting your application in production mode
+We have seen how to run a Play application in development mode, however the `run` command should not be used to run an application in production mode. When using `run`, on each request, Play checks with SBT to see if any files have changed, and this may have significant performance impacts on your application.
+
There are several ways to deploy a Play application in production mode. Let's start by using the simplest way, using a local Play installation.
-> Note, different play apps require different configuration in production. The default configuration is setup for apps that are mainly processing requests asynchronously. If your app is executing mainly blocking calls, then it's recommended to increase the number of available threads and the timeouts.
+## The application secret
+
+Before you run your application in production mode, you need to generate an application secret. To read more about how to do this, see [[Configuring the application secret|ApplicationSecret]]. In the examples below, you will see the use of `-Dapplication.secret=abcdefghijk`. You must generate your own secret to use here.
## Using the start command
The easiest way to start an application in production mode is to use the `start` command from the Play console. This requires a Play installation on the server.
```bash
-[My first application] $ start
+[my-first-app] $ start -Dapplication.secret=abcdefghijk
```
-> Note that the `run` command is only for development mode and should never be used to run an application in production. For each request a complete check is handled by sbt.
[[images/start.png]]
When you run the `start` command, Play forks a new JVM and runs the default Netty HTTP server. The standard output stream is redirected to the Play console, so you can monitor its status.
-> The server’s process id is displayed at bootstrap and written to the `RUNNING_PID` file. To kill a running Play server, it is enough to send a `SIGTERM` to the process to properly shutdown the application.
+The server’s process id is displayed at bootstrap and written to the `RUNNING_PID` file. To kill a running Play server, it is enough to send a `SIGTERM` to the process to properly shutdown the application.
If you type `Ctrl+D`, the Play console will quit, but the created server process will continue running in background. The forked JVM’s standard output stream is then closed, and logging can be read from the `logs/application.log` file.
If you type `Ctrl+C`, you will kill both JVMs: the Play console and the forked Play server.
-Alternatively you can directly use `play start` at your OS command prompt, which does the same thing:
+You can also use `activator start` at your OS command prompt to start the server without first starting the Play console:
```bash
-$ play start
+$ activator start -Dapplication.secret="abcdefghijk"
```
-> Note: the HTTP port can be set by passing -Dhttp.port system variable
-
## Using the stage task
The `start` command starts the application interactively, which means that human interaction is needed, and `Ctrl+D` is required to detach the process. This solution is not really convenient for automated deployment.
You can use the `stage` task to prepare your application to be run in place. The typical command for preparing a project to be run in place is:
```bash
-$ play clean stage
+$ activator clean stage
```
[[images/stage.png]]
This cleans and compiles your application, retrieves the required dependencies and copies them to the `target/universal/stage` directory. It also creates a `bin/<start>` script where `<start>` is the project's name. The script runs the Play server on Unix style systems and there is also a corresponding `bat` file for Windows.
-For example to start an application of the project 'foo' from the project folder you can:
+For example to start an application of the project `my-first-app` from the project folder you can:
```bash
-$ target/universal/stage/bin/foo
+$ target/universal/stage/bin/my-first-app -Dapplication.secret=abcdefghijk
```
You can also specify a different configuration file for a production environment, from the command line:
```bash
-$ target/universal/stage/bin/foo -Dconfig.file=/full/path/to/conf/application-prod.conf
+$ target/universal/stage/bin/my-first-app -Dconfig.file=/full/path/to/conf/application-prod.conf
```
-For a full description of usage invoke the start script with a "-h" option.
+For a full description of usage invoke the start script with a `-h` option.
-> **Next:** [[Creating a standalone distribution|ProductionDist]]
+> **Next:** [[Creating a standalone distribution|ProductionDist]]
@@ -71,7 +71,7 @@ $ /path/to/bin/<project-name> -Dconfig.url=http://conf.mycompany.com/conf/prod.c
Sometimes you don't want to specify another complete configuration file, but just override a bunch of specific keys. You can do that by specifying then as Java System properties:
```
-$ /path/to/bin/<project-name> -Dapplication.secret=verysecretkey -Ddb.default.password=toto
+$ /path/to/bin/<project-name> -Dapplication.secret=abcdefghijk -Ddb.default.password=toto
```
## Using environment variables
@@ -133,4 +133,4 @@ Using this file, you can stop your application using the `kill` command, for exa
$ kill $(cat /var/run/play.pid)
```
-> **Next:** [[Setting up a front end HTTP server|HTTPServer]]
+> **Next:** [[Setting up a front end HTTP server|HTTPServer]]
@@ -3,22 +3,22 @@
## Using the dist task
-The simplest way to deploy a Play application is to retrieve the source (typically via a git workflow) on the server and to use either `play start` or `play stage` to start it in place.
+The simplest way to deploy a Play application is to retrieve the source (typically via a git workflow) on the server and to use either `activator start` or `activator stage` to start it in place.
However, you sometimes need to build a binary version of your application and deploy it to the server without any dependency on Play itself. You can do this with the `dist` task.
In the Play console, simply type `dist`:
```bash
-[My first application] $ dist
+[my-first-app] $ dist
```
[[images/dist.png]]
-This produces a ZIP file containing all JAR files needed to run your application in the `target/universal` folder of your application. Alternatively you can run `play dist` directly from your OS shell prompt, which does the same thing:
+This produces a ZIP file containing all JAR files needed to run your application in the `target/universal` folder of your application. Alternatively you can run `activator dist` directly from your OS shell prompt, which does the same thing:
```bash
-$ play dist
+$ activator dist
```
> For Windows users a start script will be produced with a .bat file extension. Use this file when running a Play application on Windows.
@@ -32,7 +32,7 @@ $ play dist
> Alternatively a tar.gz file can be produced instead. Tar files retain permissions. Invoke the `universal:package-zip-tarball` task instead of the `dist` task:
>
> ```bash
-> play universal:package-zip-tarball
+> activator universal:package-zip-tarball
> ```
By default, the dist task will include the API documentation in the generated package. If this is not necessary, it can be avoided by including this line in `build.sbt`:
@@ -47,7 +47,7 @@ For builds with sub-projects, the statement above has to be applied to all sub-p
Play uses the [SBT Native Packager plugin](http://www.scala-sbt.org/sbt-native-packager/). The native packager plugin declares the `dist` task to create a zip file. Invoking the `dist` task is directly equivalent to invoking the following:
```bash
-$ play universal:package-bin
+$ activator universal:package-bin
```
Many other types of archive can be generated including:
@@ -79,7 +79,7 @@ You have to configure the repository you want to publish to, in your `build.sbt`
Then in the Play console, use the `publish` task:
```bash
-[My first application] $ publish
+[my-first-app] $ publish
```
> Check the [sbt documentation](http://www.scala-sbt.org/release/docs/index.html) to get more information about the resolvers and credentials definition.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@@ -0,0 +1 @@
+# Play sometimes gets grumpy if this file doesn't exist.
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
+ */
+package play.it.libs
+
+import play.api.test._
+import play.api.libs.Crypto
+import play.api.{PlayException, Mode}
+
+object CryptoSpec extends PlaySpecification {
+
+ val Secret = "abcdefghijklmnopqrs"
+
+ def fakeApp(m: Mode.Mode, secret: Option[String] = None) = {
+ new FakeApplication(
+ additionalConfiguration = secret.map("application.secret" -> _).toMap
+ ) {
+ override val mode = m
+ }
+ }
+
+ "Crypto" should {
+ "secret" should {
+ "load a configured secret in prod" in new WithApplication(fakeApp(Mode.Prod, Some(Secret))) {
+ Crypto.secret must_== Secret
+ }
+ "load a configured secret in dev" in new WithApplication(fakeApp(Mode.Dev, Some(Secret))) {
+ Crypto.secret must_== Secret
+ }
+ "throw an exception if secret is changeme in prod" in new WithApplication(fakeApp(Mode.Prod, Some("changeme"))) {
+ Crypto.secret must throwA[PlayException]
+ }
+ "throw an exception if no secret in prod" in new WithApplication(fakeApp(Mode.Prod)) {
+ Crypto.secret must throwA[PlayException]
+ }
+ "throw an exception if secret is blank in prod" in new WithApplication(fakeApp(Mode.Prod, Some(" "))) {
+ Crypto.secret must throwA[PlayException]
+ }
+ "throw an exception if secret is empty in prod" in new WithApplication(fakeApp(Mode.Prod, Some(""))) {
+ Crypto.secret must throwA[PlayException]
+ }
+ "generate a secret if secret is changeme in dev" in new WithApplication(fakeApp(Mode.Dev, Some("changeme"))) {
+ Crypto.secret must_!= "changeme"
+ }
+ "generate a secret if no secret in dev" in new WithApplication(fakeApp(Mode.Dev)) {
+ Crypto.secret must_!= ""
+ }
+ "generate a secret if secret is blank in dev" in new WithApplication(fakeApp(Mode.Dev, Some(" "))) {
+ Crypto.secret must_!= " "
+ }
+ "generate a secret if secret is empty in dev" in new WithApplication(fakeApp(Mode.Dev, Some(""))) {
+ Crypto.secret must_!= ""
+ }
+ }
+ }
+
+}
Oops, something went wrong.

0 comments on commit 4daa919

Please sign in to comment.