Redirect HTTP requests to HTTPS on Google App Engine and Play Framework
Asked Answered
G

3

7

I'm using flexible environment on Google App Engine to run web app written in Scala and Play Framework. I've added custom domain to my application and now my app is available both through http and https. But I need to make redirection from http to https. I've tried to manage it by doing the following, but it didn't work:

application.conf:

play.http.filters = "controllers.Filters"

controllers.Filters:

import javax.inject.Inject

import play.api.http.DefaultHttpFilters
import play.filters.cors.CORSFilter
import play.filters.https.RedirectHttpsFilter

class Filters @Inject() (corsFilter: CORSFilter, redirectHttpsFilter: RedirectHttpsFilter) extends DefaultHttpFilters(corsFilter, redirectHttpsFilter)

UPD Maybe the problem is that I need to specify https port in my Dockerfile? Here is a Dockerfile:

FROM gcr.io/google_appengine/openjdk
RUN wget http://downloads.lightbend.com/scala/2.11.8/scala-2.11.8.deb
RUN dpkg -i scala-2.11.8.deb
RUN wget https://dl.bintray.com/sbt/debian/sbt-0.13.13.deb
RUN dpkg -i sbt-0.13.13.deb
RUN apt-get update
RUN apt-get install scala sbt
RUN rm -f scala-2.11.8.deb
RUN rm -f sbt-0.13.13.deb
ADD . /appname
WORKDIR /appname
RUN chmod 755 ./docker-entrypoint.bash
ENTRYPOINT ["./docker-entrypoint.bash"]
CMD ["./target/universal/stage/bin/appname", "-Dhttp.port=8080"]
Genetic answered 31/10, 2017 at 9:12 Comment(5)
If you are using app.yaml for the configuration than you should refer to the google guide: cloud.google.com/appengine/docs/standard/python/config/…Ahders
@DanielPrzybylowski This guide is for the standard environment.Genetic
Is your app running in Prod mode?Kennedy
@FredericA. yesGenetic
This looks fine to me. Although I note that there's no package controllers definition in your Filters.scala file I'm sure this is just missing from your snippet - you'd see a big warning at startup if the controllers.Filters class isn't being found. Can you make a request with curl and show the output? Also, what happens if you write your own filter that runs before RedirectHttpsFilter and prints out the value of the request's secure field?Madaras
G
0

Here is how I achieved what I wanted:

class Filters @Inject() (corsFilter: CORSFilter, redirectHttpsFilter: HttpsFilter)
                     extends DefaultHttpFilters(corsFilter, redirectHttpsFilter)

@Singleton
class HttpsFilter extends EssentialFilter {

  override def apply(next: EssentialAction): EssentialAction =  EssentialAction { req =>
    req.headers.get("X-Forwarded-Proto") match {
      case Some("http") =>
        //Got request over HTTP
        val httpsUrl = s"https://${req.host}"
        Accumulator.done(Results.Redirect(httpsUrl))
      case _ =>
        next(req)
    }
  }
}

application.conf:

play.http.filters = "controllers.Filters"
Genetic answered 28/4, 2018 at 12:14 Comment(0)
B
1

May be you have to write another tiny application, listening on http port and issuing Location header to any incoming request?

Breeching answered 9/11, 2017 at 12:29 Comment(0)
G
0

Here is how I achieved what I wanted:

class Filters @Inject() (corsFilter: CORSFilter, redirectHttpsFilter: HttpsFilter)
                     extends DefaultHttpFilters(corsFilter, redirectHttpsFilter)

@Singleton
class HttpsFilter extends EssentialFilter {

  override def apply(next: EssentialAction): EssentialAction =  EssentialAction { req =>
    req.headers.get("X-Forwarded-Proto") match {
      case Some("http") =>
        //Got request over HTTP
        val httpsUrl = s"https://${req.host}"
        Accumulator.done(Results.Redirect(httpsUrl))
      case _ =>
        next(req)
    }
  }
}

application.conf:

play.http.filters = "controllers.Filters"
Genetic answered 28/4, 2018 at 12:14 Comment(0)
L
0

I don't know why @alex solution doesn't works for me. Even with XForwardedProto allowed in application.conf

But, instead checking this value, you can check if req is secured (boolean) in an easy mode:

@Singleton
class HttpsFilter extends EssentialFilter {
  override def apply(next: EssentialAction): EssentialAction = EssentialAction { req =>
    req.secure match {
      case false => {
        val httpsUrl= s"https://${req.host}"
        Accumulator.done(Results.Redirect(httpsUrl))
      }
      case true => next(req)
    }
  }
}
Lobotomy answered 13/8, 2020 at 9:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.