Skip to content

Commit

Permalink
#165 make the cookie secure option configurable
Browse files Browse the repository at this point in the history
  • Loading branch information
FRosner committed Nov 18, 2016
1 parent 0ba97f9 commit 52542c6
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 2 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ The following configuration properties are supported. Please refer to the [Wiki]
| -------- | ----------- | ------- |
| `broccoli.auth.mode` | Authentication and authorization mode (`none` or `conf`). | `none` |
| `broccoli.auth.conf.accounts` | User accounts when running in `conf` mode. | `[{username:administrator, password:broccoli, role:administrator, instanceRegex:".*"}]` |
| `broccoli.auth.session.timeout` | HTTPS session timeout (in seconds). | `3600` |
| `broccoli.auth.session.timeout` | Cookie session timeout (in seconds). | `3600` |
| `broccoli.auth.cookie.secure` | Whether to mark the cookie as secure (switch off if running on HTTP). | `true` |

### Web Server

Expand Down
3 changes: 3 additions & 0 deletions app/de/frosner/broccoli/conf/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ package object conf {
val AUTH_SESSION_TIMEOUT_KEY = "broccoli.auth.session.timeout"
val AUTH_SESSION_TIMEOUT_DEFAULT = 3600

val AUTH_COOKIE_SECURE_KEY = "broccoli.auth.cookie.secure"
val AUTH_COOKIE_SECURE_DEFAULT = true

val AUTH_MODE_KEY = "broccoli.auth.mode"
val AUTH_MODE_NONE = "none"
val AUTH_MODE_CONF = "conf"
Expand Down
4 changes: 3 additions & 1 deletion app/de/frosner/broccoli/controllers/AuthConfigImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ trait AuthConfigImpl extends AuthConfig with Logging {

val sessionTimeoutInSeconds = securityService.sessionTimeoutInSeconds

val cookieSecure = securityService.cookieSecure

def resolveUser(id: Id)(implicit ctx: ExecutionContext): Future[Option[User]] = Future.successful(securityService.getAccount(id))

def loginSucceeded(request: RequestHeader)(implicit ctx: ExecutionContext): Future[Result] =
Expand All @@ -52,7 +54,7 @@ trait AuthConfigImpl extends AuthConfig with Logging {

override lazy val tokenAccessor = new CookieTokenAccessor(
cookieName = AuthConfigImpl.CookieName,
cookieSecureOption = play.api.Play.maybeApplication.exists(app => play.api.Play.isProd(app)),
cookieSecureOption = play.api.Play.maybeApplication.exists(app => play.api.Play.isProd(app) && cookieSecure),
cookieHttpOnlyOption = true,
cookieDomainOption = None,
cookiePathOption = "/",
Expand Down
16 changes: 16 additions & 0 deletions app/de/frosner/broccoli/services/SecurityService.scala
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,18 @@ case class SecurityService @Inject() (configuration: Configuration) extends Logg
result
}

lazy val cookieSecure: Boolean = {
val parsed = SecurityService.tryCookieSecure(configuration) match {
case Success(cookieSecure) => cookieSecure
case Failure(throwable) =>
Logger.error(s"Error parsing ${conf.AUTH_COOKIE_SECURE_KEY}: $throwable")
System.exit(1)
throw throwable
}
Logger.info(s"${conf.AUTH_COOKIE_SECURE_KEY}=$parsed")
parsed
}

private lazy val accounts: Set[Account] = {
val accounts = SecurityService.tryAccounts(configuration) match {
case Success(userObjects) => userObjects.toSet
Expand Down Expand Up @@ -103,4 +115,8 @@ object SecurityService {
}.getOrElse(conf.AUTH_MODE_CONF_ACCOUNTS_DEFAULT)
}

private[services] def tryCookieSecure(configuration: Configuration): Try[Boolean] = Try {
configuration.getBoolean(conf.AUTH_COOKIE_SECURE_KEY).getOrElse(conf.AUTH_COOKIE_SECURE_DEFAULT)
}

}
25 changes: 25 additions & 0 deletions test/de/frosner/broccoli/services/SecurityServiceSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -182,4 +182,29 @@ class SecurityServiceSpec extends Specification {

}

"Parsing cookie secure from the configuration" should {

"work if the field is a boolean" in {
val config = ConfigFactory.empty().withValue(
conf.AUTH_COOKIE_SECURE_KEY,
ConfigValueFactory.fromAnyRef(false)
)
SecurityService.tryCookieSecure(Configuration(config)) === Success(false)
}

"fail if the field is not a boolean" in {
val config = ConfigFactory.empty().withValue(
conf.AUTH_COOKIE_SECURE_KEY,
ConfigValueFactory.fromAnyRef("bla")
)
SecurityService.tryCookieSecure(Configuration(config)).failed.get should beAnInstanceOf[Exception]
}

"take the default if the field is not defined" in {
val config = ConfigFactory.empty()
SecurityService.tryCookieSecure(Configuration(config)) === Success(conf.AUTH_COOKIE_SECURE_DEFAULT)
}

}

}

0 comments on commit 52542c6

Please sign in to comment.